<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>iTopCN – 修改数据模型</title><link>/docs/customization/how-to/datamodel/</link><description>Recent content in 修改数据模型 on iTopCN</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Fri, 27 Jun 2025 00:00:00 +0000</lastBuildDate><atom:link href="/docs/customization/how-to/datamodel/index.xml" rel="self" type="application/rss+xml"/><item><title>Docs: n:n 自反与对称关系</title><link>/docs/customization/how-to/datamodel/n-n-reflexive-relation/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/n-n-reflexive-relation/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何创建类与自身的对称多对多关系。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:n-n-reflexive-relation">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>创建类与自身的对称关系，例如人员的同事关系。若 John 是 Anna 的同事，则 Anna 也是 John 的同事。&lt;/p>
&lt;p>iTop 默认的多对多关系不是对称的。本教程通过自动创建双向记录来实现对称性。&lt;/p>
&lt;h2 id="人员同事关系">人员同事关系&lt;/h2>
&lt;h3 id="核心思路">核心思路&lt;/h3>
&lt;p>当用户创建 (src_person = John, dest_person = Anna) 时，后台自动创建其镜像 (src_person = Anna, dest_person = John)。&lt;/p>
&lt;h3 id="afterinsert">AfterInsert&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">AfterInsert&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oSearch&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">DBSearch&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">FromOQL&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;SELECT lnkPersonToPerson WHERE src_person_id = :src_id AND dest_person_id = :dest_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oSet&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">DBObjectSet&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oSearch&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;src_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;dest_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Count&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oLnk&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">NewObject&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;lnkPersonToPerson&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oLnk&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DBInsert&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="afterupdate">AfterUpdate&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">AfterUpdate&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$aChanges&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ListPreviousValuesForUpdatedAttributes&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sPrevSrc&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">array_key_exists&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$aChanges&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">?&lt;/span> &lt;span style="color:#000">$aChanges&lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">]&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">:&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sPrevDest&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">array_key_exists&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$aChanges&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">?&lt;/span> &lt;span style="color:#000">$aChanges&lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">]&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">:&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oSearch&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">DBSearch&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">FromOQL&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;SELECT lnkPersonToPerson WHERE src_person_id = :src_id AND dest_person_id = :dest_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oSet&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">DBObjectSet&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oSearch&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;src_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$sPrevDest&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;dest_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$sPrevSrc&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Count&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;gt;&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">while&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oLnk&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Fetch&lt;/span>&lt;span style="color:#000;font-weight:bold">())&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oLnk&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oLnk&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oLnk&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DBUpdate&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span> &lt;span style="color:#204a87;font-weight:bold">else&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oSearchNew&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">DBSearch&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">FromOQL&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;SELECT lnkPersonToPerson WHERE src_person_id = :src_id AND dest_person_id = :dest_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oSetNew&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">DBObjectSet&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oSearchNew&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;src_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;dest_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oSetNew&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Count&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">===&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oLnk&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">NewObject&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;lnkPersonToPerson&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oLnk&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DBInsert&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="afterdelete">AfterDelete&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">AfterDelete&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oSearch&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">DBSearch&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">FromOQL&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;SELECT lnkPersonToPerson WHERE src_person_id = :src_id AND dest_person_id = :dest_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oSet&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">DBObjectSet&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oSearch&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;src_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;dest_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;dest_id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;src_person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Count&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;gt;&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">while&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oLnk&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Fetch&lt;/span>&lt;span style="color:#000;font-weight:bold">())&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oLnk&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DBDelete&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="networkdevice--connectableci">NetworkDevice &amp;amp; ConnectableCI&lt;/h2>
&lt;p>此用例来自 iTop 默认数据模型，比上面的更复杂，因为有时对称有时不对称，取决于 ConnectableCI 是否也是 NetworkDevice。&lt;/p>
&lt;h3 id="afterinsert-1">AfterInsert&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">AfterInsert&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oDevice&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">GetObject&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;ConnectableCI&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;connectableci_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">is_object&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oDevice&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">get_class&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oDevice&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;NetworkDevice&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sOQL&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#4e9a06">&amp;#34;SELECT lnkConnectableCIToNetworkDevice
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> WHERE connectableci_id = :device AND networkdevice_id = :network
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> AND network_port = :nwport AND device_port = :devport&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oConnectionSet&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">DBObjectSet&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">DBObjectSearch&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">FromOQL&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sOQL&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;network&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;connectableci_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;device&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;networkdevice_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;devport&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;network_port&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;nwport&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;device_port&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oConnectionSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Count&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sLink&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;connection_type&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sConnLink&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sLink&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;uplink&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">?&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;downlink&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">:&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;uplink&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oNewLink&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">lnkConnectableCIToNetworkDevice&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oNewLink&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;networkdevice_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;connectableci_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oNewLink&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;connectableci_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;networkdevice_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oNewLink&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;network_port&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;device_port&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oNewLink&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;device_port&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;network_port&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oNewLink&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;connection_type&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sConnLink&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oNewLink&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DBInsert&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="afterdelete-1">AfterDelete&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">AfterDelete&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oDevice&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">GetObject&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;ConnectableCI&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;connectableci_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span> &lt;span style="color:#204a87;font-weight:bold">false&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">is_object&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oDevice&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">get_class&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oDevice&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;NetworkDevice&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sOQL&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#4e9a06">&amp;#34;SELECT lnkConnectableCIToNetworkDevice
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> WHERE connectableci_id = :device AND networkdevice_id = :network
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> AND network_port = :nwport AND device_port = :devport&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oConnectionSet&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">DBObjectSet&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">DBObjectSearch&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">FromOQL&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sOQL&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;network&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;connectableci_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;device&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;networkdevice_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;devport&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;network_port&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;nwport&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;device_port&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">while&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oConnection&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oConnectionSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Fetch&lt;/span>&lt;span style="color:#000;font-weight:bold">())&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oConnection&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DBDelete&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:n-n-reflexive-relation">https://www.itophub.io/wiki/page?id=3_2_0:customization:n-n-reflexive-relation&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/n-n-reflexive-relation.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 创建新的 CI 类：Monitor</title><link>/docs/customization/how-to/datamodel/add-class-sample/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-class-sample/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何创建新的 iTop 模块以添加自定义 CI 类。以创建 Monitor（显示器）类为例。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-class-sample">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>本教程将创建一个新的 CI 类 &lt;strong>Monitor&lt;/strong>，继承自 PhysicalDevice，并添加一个 &lt;code>technology&lt;/code> 字段来区分 CRT 和 LCD 显示器。&lt;/p>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;p>Combodo 客户可直接在 ITSM Designer 中创建新类。&lt;/p>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="创建模块">创建模块&lt;/h3>
&lt;p>使用扩展创建向导：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>标签&lt;/th>
&lt;th>值&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>模块名称&lt;/td>
&lt;td>sample-add-class&lt;/td>
&lt;td>以 &lt;code>itop-&lt;/code> 和 &lt;code>combodo-&lt;/code> 开头的名称保留&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>模块标签&lt;/td>
&lt;td>Add Class Sample&lt;/td>
&lt;td>安装向导中显示的标签&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>模块版本&lt;/td>
&lt;td>1.0.0&lt;/td>
&lt;td>使用 X.Y.Z 三位版本号&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>类别&lt;/td>
&lt;td>business&lt;/td>
&lt;td>修改数据模型的模块使用 &amp;lsquo;business&amp;rsquo; 类别&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>依赖&lt;/td>
&lt;td>itop-config-mgmt/2.0.0, itop-endusers-devices/2.0.0&lt;/td>
&lt;td>依赖配置管理和终端用户设备模块&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="添加-monitor-类">添加 Monitor 类&lt;/h3>
&lt;p>编辑 &lt;code>datamodel.sample-add-class.xml&lt;/code>，在 &lt;code>&amp;lt;classes&amp;gt;&lt;/code> 内添加：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Monitor&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;parent&amp;gt;&lt;/span>PhysicalDevice&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/parent&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;category&amp;gt;&lt;/span>bizmodel,searchable&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/category&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;abstract&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/abstract&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;key_type&amp;gt;&lt;/span>autoincrement&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/key_type&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;db_table&amp;gt;&lt;/span>monitor&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/db_table&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;db_key_field&amp;gt;&lt;/span>id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/db_key_field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;db_final_class_field/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;naming&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attributes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attributes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/naming&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;icon&amp;gt;&lt;/span>images/monitor.png&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/icon&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;reconciliation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attributes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;org_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;organization_name&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attributes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/reconciliation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;technology&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeEnum&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&amp;gt;&lt;/span>crt&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&amp;gt;&lt;/span>lcd&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>technology&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;default_value/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;display_style&amp;gt;&lt;/span>radio_horizontal&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/display_style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;org_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>20&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;status&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>30&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;business_criticity&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>40&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;location_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>50&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;brand_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>60&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;model_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>70&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;technology&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>75&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;serialnumber&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>80&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;asset_number&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>90&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;!-- ... 其他字段 ... --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;search&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;!-- ... --&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/search&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;list&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;!-- ... --&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/list&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加类图标">添加类图标&lt;/h3>
&lt;p>在 &lt;code>extensions/sample-add-class/images/&lt;/code> 目录下放置 &lt;code>monitor.png&lt;/code> 图标文件。&lt;/p>
&lt;h3 id="修复标签">修复标签&lt;/h3>
&lt;p>编辑 &lt;code>en.dict.sample-add-class.php&lt;/code>，添加字典条目：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">Dict&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">Add&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;EN US&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;English&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;English&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;Class:Monitor&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;Monitor&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;Class:Monitor+&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;A computer display&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;Class:Monitor/Attribute:technology&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;Technology&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;Class:Monitor/Attribute:technology+&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;Technology used for the display&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;Class:Monitor/Attribute:technology/Value:crt&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;CRT&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;Class:Monitor/Attribute:technology/Value:lcd&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;LCD&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加到-modeltype">添加到 Model.type&lt;/h3>
&lt;p>将 Monitor 添加到 Model 类的 type 枚举值中：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Model&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;type&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeEnum&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Monitor&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>Monitor&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加仪表盘项">添加仪表盘项&lt;/h3>
&lt;p>将 Monitor 添加到配置管理概览仪表盘的 &amp;ldquo;终端用户设备&amp;rdquo; 区域：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;menus&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;menu&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ConfigManagementOverview&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;DashboardMenuNode&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;definition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;cells&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;cell&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;2&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dashlets&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dashlet&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;99&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;DashletBadge&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>8&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&amp;gt;&lt;/span>Monitor&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dashlet&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dashlets&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/cell&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/cells&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/definition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/menu&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/menus&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="部署">部署&lt;/h2>
&lt;p>将模块文件夹复制到目标 iTop 的 &lt;code>extensions&lt;/code> 目录并运行安装。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-class-sample">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-class-sample&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/add-class-sample.txt · Last modified: 2026/03/16 14:02 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 创建新配置文件</title><link>/docs/customization/how-to/datamodel/add-profile-sample/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-profile-sample/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何创建新的 iTop 配置文件以控制用户访问权限。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-profile-sample">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>本教程将创建两个新配置文件：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Read-Only Except Requests&lt;/strong> — 允许浏览所有对象，但只能创建/修改用户请求&lt;/li>
&lt;li>&lt;strong>Read-Only No Portal Access&lt;/strong> — 纯只读配置，允许浏览但禁止修改任何内容&lt;/li>
&lt;/ul>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;h3 id="创建新配置文件">创建新配置文件&lt;/h3>
&lt;ol>
&lt;li>导航到 &lt;strong>User Rights&lt;/strong> Designer 标签页&lt;/li>
&lt;li>点击工具栏中的创建按钮&lt;/li>
&lt;li>为新配置文件添加组&lt;/li>
&lt;li>为每个组定义权限：Allow（允许）、Undefined（未定义/不允许）、Denied（明确拒绝）&lt;/li>
&lt;/ol>
&lt;h3 id="创建新组">创建新组&lt;/h3>
&lt;p>若现有组不满足需求，可创建新组：&lt;/p>
&lt;ol>
&lt;li>点击工具栏中的创建按钮&lt;/li>
&lt;li>使用中心窗格的树状视图勾选要添加到组中的类&lt;/li>
&lt;/ol>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="创建模块">创建模块&lt;/h3>
&lt;p>使用扩展创建向导：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>标签&lt;/th>
&lt;th>值&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>模块名称&lt;/td>
&lt;td>sample-add-profile&lt;/td>
&lt;td>以 &lt;code>itop-&lt;/code> 和 &lt;code>combodo-&lt;/code> 开头的名称保留&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>模块标签&lt;/td>
&lt;td>Add Profile Sample&lt;/td>
&lt;td>安装向导中显示的标签&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>模块版本&lt;/td>
&lt;td>1.0.0&lt;/td>
&lt;td>使用 X.Y.Z 三位版本号&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>类别&lt;/td>
&lt;td>business&lt;/td>
&lt;td>修改数据模型的模块使用 &amp;lsquo;business&amp;rsquo; 类别&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>依赖&lt;/td>
&lt;td>itop-profiles-itil/1.0.0&lt;/td>
&lt;td>依赖 iTop ITIL 配置文件模块&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="声明新配置文件">声明新配置文件&lt;/h3>
&lt;p>编辑 &lt;code>datamodel.sample-add-profile.xml&lt;/code>，在 &lt;code>&amp;lt;user_rights&amp;gt;&lt;/code> 内添加：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;profiles&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;profile&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;50&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;name&amp;gt;&lt;/span>Read-Only Except Requests&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/name&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;description&amp;gt;&lt;/span>Users with this profile are allowed to browse through all objects in the application and to create/modify user requests (either through the portal or in the normal application)&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/description&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;groups&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;group&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Portal&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;write&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;delete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/group&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;group&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;UserRequest&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;action:write&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;stimulus:ev_close&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;stimulus&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;stimulus:ev_reopen&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;stimulus&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/group&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;group&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;*&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;action:read&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;action:bulk read&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/group&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/groups&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/profile&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;profile&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;51&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;name&amp;gt;&lt;/span>Read-Only No Portal Access&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/name&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;description&amp;gt;&lt;/span>Users with this profile are allowed to browse through all objects in the application but not to modify anything (even through the portal)&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/description&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;groups&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;group&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;*&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;action:read&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;action:bulk read&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/group&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/groups&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/profile&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/profiles&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="说明">说明&lt;/h3>
&lt;ul>
&lt;li>第一个配置文件（id=50）是 &amp;ldquo;Portal User&amp;rdquo; 配置文件的克隆，但允许在标准界面中导航&lt;/li>
&lt;li>第二个配置文件（id=51）是纯只读配置&lt;/li>
&lt;li>组 &lt;code>*&lt;/code> 表示&amp;quot;任何类&amp;quot;&lt;/li>
&lt;li>使用的组定义在 &lt;code>itop-profiles-itil&lt;/code> 模块中&lt;/li>
&lt;/ul>
&lt;h3 id="激活配置文件">激活配置文件&lt;/h3>
&lt;p>修改完成后，需要&lt;strong>重新运行安装&lt;/strong>以激活新配置文件。&lt;/p>
&lt;h2 id="部署">部署&lt;/h2>
&lt;p>将模块文件夹复制到目标 iTop 的 &lt;code>extensions&lt;/code> 目录并运行安装。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-profile-sample">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-profile-sample&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/add-profile-sample.txt · Last modified: 2026/03/16 14:03 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 从 Ticket 中移除字段</title><link>/docs/customization/how-to/datamodel/remove-field/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/remove-field/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何从 iTop 类中完全移除字段。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:remove-field">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>移除字段需要识别该字段在 iTop XML 数据模型中的所有使用位置。以 UserRequest 的 &lt;code>urgency&lt;/code> 字段为例，需要检查：&lt;/p>
&lt;ul>
&lt;li>字段定义（&lt;code>fields/field@urgency&lt;/code>）&lt;/li>
&lt;li>类属性（naming、order、reconciliation 等）&lt;/li>
&lt;li>生命周期（lifecycle）&lt;/li>
&lt;li>展示（presentation）&lt;/li>
&lt;li>方法（methods）&lt;/li>
&lt;li>门户表单（module_designs/module_design@itop-portal/forms）&lt;/li>
&lt;li>字典条目&lt;/li>
&lt;li>OQL 查询（filter、Dashlets、Audit rules、Notifications 等）&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>移除标准数据模型中的字段可能破坏依赖该字段的 iTop 扩展的兼容性。&lt;/p>
&lt;/blockquote>
&lt;h2 id="仅隐藏字段">仅隐藏字段&lt;/h2>
&lt;p>在某些情况下，仅隐藏字段给用户可能已足够。&lt;/p>
&lt;h3 id="在门户中隐藏">在门户中隐藏&lt;/h3>
&lt;p>创建表单时隐藏：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;form&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ticket-create&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;twig&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redefine&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;div&lt;/span> &lt;span style="color:#c4a000">class=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;row&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;div&lt;/span> &lt;span style="color:#c4a000">class=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;col-sm-6&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;div&lt;/span> &lt;span style="color:#c4a000">class=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;form_field&amp;#34;&lt;/span> &lt;span style="color:#c4a000">data-field-id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;impact&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;/div&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/div&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;div&lt;/span> &lt;span style="color:#c4a000">class=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;col-sm-6&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;!-- 从默认门户中移除 urgency --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;!-- &amp;lt;div class=&amp;#34;form_field&amp;#34; data-field-id=&amp;#34;urgency&amp;#34;&amp;gt;&amp;lt;/div&amp;gt; --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/div&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/div&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/twig&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/form&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="在控制台中隐藏">在控制台中隐藏&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;col:col2&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;fieldset:Ticket:Type&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;urgency&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;delete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>仅隐藏不会完全移除字段，仍可通过 CSV 导出、列表配置、CSV 导入、REST/JSON API 访问。&lt;/p>
&lt;/blockquote>
&lt;h2 id="完全移除字段">完全移除字段&lt;/h2>
&lt;h3 id="字段定义">字段定义&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;urgency&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;delete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="类属性">类属性&lt;/h3>
&lt;p>检查 &lt;code>urgency&lt;/code> 是否用于：&lt;/p>
&lt;ul>
&lt;li>friendlyname&lt;/li>
&lt;li>协调字段（CSV 导入）&lt;/li>
&lt;li>过时逻辑&lt;/li>
&lt;li>唯一性规则&lt;/li>
&lt;/ul>
&lt;h3 id="生命周期标志">生命周期标志&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;resolved&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;urgency&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;delete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/flags&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="方法">方法&lt;/h3>
&lt;p>检查 PHP 方法中是否有 &lt;code>$this-&amp;gt;Get('urgency')&lt;/code> 引用。例如 &lt;code>ComputePriority&lt;/code> 方法需要修改。&lt;/p>
&lt;h3 id="展示">展示&lt;/h3>
&lt;p>从 &lt;code>search&lt;/code>、&lt;code>list&lt;/code> 和 &lt;code>default_search&lt;/code> 中移除：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;search&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;urgency&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;delete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/search&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="字典条目">字典条目&lt;/h3>
&lt;p>理论上应删除对应字典条目，但不删除不影响 iTop 行为。&lt;/p>
&lt;h3 id="oql-查询">OQL 查询&lt;/h3>
&lt;p>检查以下位置是否使用了该字段：&lt;/p>
&lt;ul>
&lt;li>数据模型中的 filter 标签&lt;/li>
&lt;li>Dashlets&lt;/li>
&lt;li>查询短语&lt;/li>
&lt;li>审计规则&lt;/li>
&lt;li>书签 URL&lt;/li>
&lt;li>通知&lt;/li>
&lt;li>配置文件参数&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:remove-field">https://www.itophub.io/wiki/page?id=3_2_0:customization:remove-field&lt;/a>&lt;/p>
&lt;p>2024/09/10 10:25 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/remove-field.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 定义密码策略</title><link>/docs/customization/how-to/datamodel/password-policy/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/password-policy/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何创建自定义密码策略验证器。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:password-policy">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>iTop 不内置复杂的密码策略，但可以通过扩展实现自定义验证器。&lt;/p>
&lt;h2 id="可能的策略">可能的策略&lt;/h2>
&lt;h3 id="黑名单策略">黑名单策略&lt;/h3>
&lt;p>检查用户密码是否不在弱密码列表中。实现简单，本教程以此为例。&lt;/p>
&lt;h3 id="密码不能与前密码相同">密码不能与前密码相同&lt;/h3>
&lt;p>更复杂，因为：&lt;/p>
&lt;ul>
&lt;li>iTop 只存储密码哈希&lt;/li>
&lt;li>盐值是随机的且难以提取&lt;/li>
&lt;/ul>
&lt;p>实现概要：&lt;/p>
&lt;ul>
&lt;li>验证器需实现 &lt;code>iApplicationObjectExtension::OnDBUpdate()&lt;/code> 和 &lt;code>UserLocalPasswordValidator&lt;/code> 接口&lt;/li>
&lt;li>将之前的密码哈希存储到专用类中&lt;/li>
&lt;li>使用明文密码与哈希列表对比（不能比较两个哈希）&lt;/li>
&lt;li>建议限制存储的哈希数量&lt;/li>
&lt;/ul>
&lt;h2 id="实现验证器">实现验证器&lt;/h2>
&lt;p>创建实现 &lt;code>UserLocalPasswordValidator&lt;/code> 接口的类：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">class&lt;/span> &lt;span style="color:#000">MyCustomPasswordValidator&lt;/span> &lt;span style="color:#204a87;font-weight:bold">implements&lt;/span> &lt;span style="color:#000">UserLocalPasswordValidator&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 您的代码...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>验证时返回 &lt;code>ValidatePassword&lt;/code> 实例：&lt;/p>
&lt;ul>
&lt;li>密码有效：&lt;code>new UserLocalPasswordValidity(true)&lt;/code>&lt;/li>
&lt;li>密码无效：&lt;code>new UserLocalPasswordValidity(false, $sMessage)&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>&lt;code>$sMessage&lt;/code> 必须是已翻译的消息，按约定使用格式：
&lt;code>'Error:UserLocalPasswordValidator:&amp;lt;YourClassName&amp;gt;/ValidationFailed'&lt;/code>&lt;/p>
&lt;h2 id="示例黑名单验证器">示例：黑名单验证器&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">class&lt;/span> &lt;span style="color:#000">UserPasswordPolicyBlacklist&lt;/span> &lt;span style="color:#204a87;font-weight:bold">implements&lt;/span> &lt;span style="color:#000">UserLocalPasswordValidator&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">__construct&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">ValidatePassword&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$proposedValue&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">UserLocal&lt;/span> &lt;span style="color:#000">$oUserLocal&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$config&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sBlacklistFile&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">APPROOT&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;data/passwordBlacklist.txt&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$handle&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">@&lt;/span>&lt;span style="color:#000">fopen&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sBlacklistFile&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#34;r&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">!&lt;/span> &lt;span style="color:#000">$handle&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">UserLocalPasswordValidity&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">false&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;Unknown error : Failed to read the password blacklist.&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">try&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">while&lt;/span> &lt;span style="color:#000;font-weight:bold">((&lt;/span>&lt;span style="color:#000">$sBlackListPwd&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">fgets&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$handle&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">4096&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">!==&lt;/span> &lt;span style="color:#204a87;font-weight:bold">false&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">trim&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sBlackListPwd&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#000">trim&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$proposedValue&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sMessage&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">Dict&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">S&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;Error:UserLocalPasswordValidator:UserPasswordPolicyBlacklist/ValidationFailed&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">UserLocalPasswordValidity&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">false&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sMessage&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">finally&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">fclose&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$handle&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">UserLocalPasswordValidity&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>data/passwordBlacklist.txt&lt;/code> 每行一个禁用密码。可使用 &lt;a href="https://github.com/danielmiessler/SecLists/blob/master/Passwords/darkweb2017-top10000.txt">SecLists&lt;/a> 中的前 10000 个常用密码。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:password-policy">https://www.itophub.io/wiki/page?id=3_2_0:customization:password-policy&lt;/a>&lt;/p>
&lt;p>2024/09/10 10:25 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/password-policy.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 定义依赖关系</title><link>/docs/customization/how-to/datamodel/neighbours/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/neighbours/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在 iTop 类之间定义新的依赖关系，用于影响分析。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:neighbours">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>假设创建了 FunctionalCI 下的新类 &amp;ldquo;Truc&amp;rdquo;，该类影响 ApplicationSolution 或 BusinessProcess。且影响规则因每个 ApplicationSolution 和 BusinessProcess 而异。&lt;/p>
&lt;h2 id="实现">实现&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Truc&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;parent&amp;gt;&lt;/span>FunctionalCI&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/parent&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;properties&amp;gt;&lt;/span>...&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;functionalci_id&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeExternalKey&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>functionalci_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filter&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> SELECT FunctionalCI WHERE finalclass IN (&amp;#39;ApplicationSolution&amp;#39;, &amp;#39;BusinessProcess&amp;#39;)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> ]]&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target_class&amp;gt;&lt;/span>FunctionalCI&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;on_target_delete&amp;gt;&lt;/span>DEL_MANUAL&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/on_target_delete&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;tracking_level&amp;gt;&lt;/span>all&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/tracking_level&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;allow_target_creation&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/allow_target_creation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;relations&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;relation&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;impacts&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;neighbours&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;neighbour&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;business&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&amp;gt;&lt;/span>functionalci_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/neighbour&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/neighbours&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/relation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/relations&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;FunctionalCI&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;merge&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;trucs_list&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeLinkedSet&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;linked_class&amp;gt;&lt;/span>Truc&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/linked_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;ext_key_to_me&amp;gt;&lt;/span>functionalci_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/ext_key_to_me&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;count_min&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/count_min&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;count_max&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/count_max&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;edit_mode&amp;gt;&lt;/span>add_remove&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/edit_mode&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;duplicates/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redundancy&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeRedundancySettings&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>redundancy&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;relation_code&amp;gt;&lt;/span>impacts&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/relation_code&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;from_class&amp;gt;&lt;/span>Truc&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/from_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;neighbour_id&amp;gt;&lt;/span>business&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/neighbour_id&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;enabled&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/enabled&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;enabled_mode&amp;gt;&lt;/span>user&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/enabled_mode&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;min_up&amp;gt;&lt;/span>1&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/min_up&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;min_up_mode&amp;gt;&lt;/span>user&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/min_up_mode&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;min_up_type&amp;gt;&lt;/span>count&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/min_up_type&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;BusinessProcess&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;merge&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;trucs_list&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>110&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ApplicationSolution&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;merge&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;trucs_list&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>110&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="关键点">关键点&lt;/h3>
&lt;ul>
&lt;li>&lt;code>relation id=&amp;quot;impacts&amp;quot;&lt;/code> 必须命名为 &amp;ldquo;impacts&amp;rdquo; 才能在影响分析中使用&lt;/li>
&lt;li>&lt;code>neighbour&lt;/code> 的 &lt;code>attribute&lt;/code> 可以是指向外部键、LinkedSet 或一对查询（向下和向上）&lt;/li>
&lt;li>&lt;code>AttributeRedundancySettings&lt;/code> 允许配置冗余规则&lt;/li>
&lt;li>&lt;code>min_up&lt;/code> 定义最少需要多少个 &amp;ldquo;Truc&amp;rdquo; 处于运行状态&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:neighbours">https://www.itophub.io/wiki/page?id=3_2_0:customization:neighbours&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/neighbours.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 合并状态</title><link>/docs/customization/how-to/datamodel/meta-enum/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/meta-enum/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何使用 AttributeMetaEnum 创建基于子类字段值的合并状态。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:meta-enum">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>Ticket 类使用特殊的 &lt;code>AttributeMetaEnum&lt;/code> 类型属性来创建聚合状态，基于子工单类字段值自动计算。&lt;/p>
&lt;p>您可以为 FunctionalCI 类创建类似的 &lt;code>AttributeMetaEnum&lt;/code> 字段，基于一个或多个子类上定义的字段值计算。&lt;/p>
&lt;h2 id="添加计算状态">添加计算状态&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;FunctionalCI&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_created_in=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;itop-config-mgmt&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;operational_status&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeMetaEnum&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;production&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;code&amp;gt;&lt;/span>production&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;implementation&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;code&amp;gt;&lt;/span>implementation&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;obsolete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;code&amp;gt;&lt;/span>obsolete&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>operational_status&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;default_value&amp;gt;&lt;/span>production&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/default_value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;mappings&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;mapping&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;FunctionalCI&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attcode&amp;gt;&lt;/span>status&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attcode&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalues&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalue&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;implementation&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;implementation&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalue&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalue&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;obsolete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;obsolete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;inactive&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalue&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalues&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/mapping&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/mappings&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>default_value&lt;/code>：若没有任何映射适用，则使用此默认值&lt;/li>
&lt;li>&lt;code>mapping&lt;/code> 的 ID 必须是当前类或子类&lt;/li>
&lt;li>&lt;code>attcode&lt;/code>：至少一个子类上定义的属性代码&lt;/li>
&lt;li>可定义多个映射，第一个匹配的映射决定 AttributeMetaEnum 的值&lt;/li>
&lt;/ul>
&lt;h2 id="修改计算状态">修改计算状态&lt;/h2>
&lt;p>示例：添加新的 &lt;code>escalated&lt;/code> 值，并修改 UserRequest 的 &lt;code>rejected&lt;/code> 映射逻辑：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;operational_status&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeMetaEnum&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;escalated&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;code&amp;gt;&lt;/span>escalated&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;mappings&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;mapping&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Ticket&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalues&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalue&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;escalated&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;escalated_tto&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;escalated_ttr&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalue&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalue&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;closed&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;rejected&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;delete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalue&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalues&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/mapping&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;mapping&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Change&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attcode&amp;gt;&lt;/span>status&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attcode&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalues&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalue&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;closed&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;closed&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;rejected&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalue&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalues&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/mapping&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/mappings&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>此示例中：&lt;/p>
&lt;ul>
&lt;li>UserRequest 的 &lt;code>rejected&lt;/code> 状态映射为 &lt;code>ongoing&lt;/code>（Ticket 的默认映射）&lt;/li>
&lt;li>Change 的 &lt;code>rejected&lt;/code> 状态仍映射为 &lt;code>closed&lt;/code>&lt;/li>
&lt;/ul>
&lt;h2 id="默认-31-定义">默认 3.1 定义&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;operational_status&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeMetaEnum&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ongoing&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;code&amp;gt;&lt;/span>ongoing&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;resolved&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;code&amp;gt;&lt;/span>resolved&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;main_color&amp;gt;&lt;/span>$ibo-lifecycle-success-state-primary-color&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/main_color&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;complementary_color&amp;gt;&lt;/span>$ibo-lifecycle-success-state-secondary-color&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/complementary_color&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;decoration_classes&amp;gt;&lt;/span>fas fa-check&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/decoration_classes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;closed&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;code&amp;gt;&lt;/span>closed&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;main_color&amp;gt;&lt;/span>$ibo-lifecycle-frozen-state-primary-color&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/main_color&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;complementary_color&amp;gt;&lt;/span>$ibo-lifecycle-frozen-state-secondary-color&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/complementary_color&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;decoration_classes/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;default_style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;main_color&amp;gt;&lt;/span>$ibo-lifecycle-neutral-state-primary-color&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/main_color&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;complementary_color&amp;gt;&lt;/span>$ibo-lifecycle-neutral-state-secondary-color&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/complementary_color&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;decoration_classes/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/default_style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>operational_status&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;default_value&amp;gt;&lt;/span>ongoing&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/default_value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;mappings&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;mapping&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Ticket&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attcode&amp;gt;&lt;/span>status&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attcode&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalues&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalue&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;resolved&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;resolved&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalue&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;metavalue&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;closed&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;closed&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;rejected&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalue&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/metavalues&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/mapping&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/mappings&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:meta-enum">https://www.itophub.io/wiki/page?id=3_2_0:customization:meta-enum&lt;/a>&lt;/p>
&lt;p>Last modified: 2026/01/14 17:10 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/meta-enum.txt · Last modified: 2026/01/14 17:10 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 强制字段始终必填</title><link>/docs/customization/how-to/datamodel/mandatory-field-always/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/mandatory-field-always/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何强制字段在所有情况下必填。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-field-always">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>本用例强制要求在所有 PhysicalDevice 及其子类（Server、Mobile Phone、Rack、Tablet、PDU 等）上填写 &amp;ldquo;location&amp;rdquo; 字段。&lt;/p>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;ol>
&lt;li>打开 PhysicalDevice 类&lt;/li>
&lt;li>编辑 &lt;code>location_id&lt;/code> 字段&lt;/li>
&lt;li>在弹窗中勾选 &lt;strong>Mandatory&lt;/strong> 复选框&lt;/li>
&lt;/ol>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;p>由于 &lt;code>location_id&lt;/code> 字段直接在 PhysicalDevice 类上声明，只需将 &lt;code>is_null_allowed&lt;/code> 设为 &lt;code>false&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;PhysicalDevice&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;location_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redefine&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="迁移注意事项">迁移注意事项&lt;/h2>
&lt;p>在 Setup（或工具包）时，若已有 PhysicalDevice 未记录位置，将收到错误消息。可以在 iTop 的 DB tools 菜单中重新运行此检查。修复对象不会阻止其打开和修改，但 DataSynchro 或 REST/JSON 脚本在修改其他字段时会失败。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-field-always">https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-field-always&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/mandatory-field-always.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 实现密码过期</title><link>/docs/customization/how-to/datamodel/password-expiration/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/password-expiration/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何实现密码过期功能。从 iTop 3.1.0 开始，此功能已内置在 Password Expiration Management 模块中。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:password-expiration">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;blockquote>
&lt;p>&lt;strong>注意&lt;/strong>：从 iTop 3.1.0 开始，此功能已内置在 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:password-expiration">Password Expiration Management&lt;/a> 模块中，无需再手动实现。&lt;/p>
&lt;/blockquote>
&lt;p>本教程描述如何强制现有用户更改密码以符合新添加的复杂性策略。管理员将所有用户的 &lt;code>expiration&lt;/code> 标志设为 &lt;code>expired&lt;/code>，用户登录时将被要求更改密码。&lt;/p>
&lt;h2 id="插入检查点">插入检查点&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">class&lt;/span> &lt;span style="color:#000">MyClass&lt;/span> &lt;span style="color:#204a87;font-weight:bold">extends&lt;/span> &lt;span style="color:#000">AbstractLoginFSMExtension&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">ListSupportedLoginModes&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;form&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">protected&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">OnUsersOK&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&lt;/span>&lt;span style="color:#000">$iErrorCode&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">/* 在此处添加特定代码 */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#000">LoginWebPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">LOGIN_FSM_CONTINUE&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="检查密码是否过期">检查密码是否过期&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">$oUser&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">UserRights&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">GetUserObject&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oUser&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;expiration&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;expired&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">/* 添加更多代码 */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="请求新密码">请求新密码&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">DisplayChangePwdForm&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$bFailedLogin&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">false&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sIssue&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">null&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oTwigContext&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">LoginTwigRenderer&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$aVars&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oTwigContext&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">GetDefaultVars&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$aVars&lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;bFailedLogin&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">]&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$bFailedLogin&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$aVars&lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;sIssue&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">]&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$sIssue&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oTwigContext&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Render&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;changepwdform.html.twig&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$aVars&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>模板 &lt;code>iTop/templates/login/password/changepwdform.html.twig&lt;/code> 可复用，需移除 &lt;code>old_pwd&lt;/code> 部分。同时有 &lt;code>changepwdform.js.twig&lt;/code> 控制两次输入是否相等以及密码是否符合策略。&lt;/p>
&lt;h2 id="保存新密码">保存新密码&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">$sNewPwd&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">utils&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">ReadPostedParam&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;new_pwd&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;raw_data&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">$oUser&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;password&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sNewPwd&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">$oUser&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;expiration&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;limited&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">$oUser&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DB_Update&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="错误处理">错误处理&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">try&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">!&lt;/span>&lt;span style="color:#000">UserRights&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">ChangePassword&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sOldPwd&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sNewPwd&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oPage&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">self&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">NewLoginWebPage&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DisplayChangePwdForm&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">output&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">exit&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">catch&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">CoreCannotSaveObjectException&lt;/span> &lt;span style="color:#000">$e&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oPage&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">self&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">NewLoginWebPage&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DisplayChangePwdForm&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$e&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">getIssue&lt;/span>&lt;span style="color:#000;font-weight:bold">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">output&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">exit&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="注意事项">注意事项&lt;/h2>
&lt;p>当扩展自动化过期行为时，应修改 &lt;code>UserLocal:password:expiration&lt;/code> 的翻译，以反映此行为。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:password-expiration">https://www.itophub.io/wiki/page?id=3_2_0:customization:password-expiration&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/password-expiration.txt · Last modified: 2025/07/03 12:43 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 属性的使用与限制</title><link>/docs/customization/how-to/datamodel/attribute-limitation/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/attribute-limitation/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍 iTop 中各种属性类型的使用限制和替代方案。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:attribute-limitation">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>iTop 提供了多种属性类型，但并非每种属性都能在任何地方使用。本文档说明各种限制和替代方案。&lt;/p>
&lt;h2 id="字段在子类上的覆盖">字段在子类上的覆盖&lt;/h2>
&lt;p>字段在单个类上定义，具有属性：默认值、允许值、是否必填、依赖关系等。&lt;/p>
&lt;p>在每个子类上，可以：&lt;/p>
&lt;ul>
&lt;li>定义字段的显示位置&lt;/li>
&lt;li>覆盖标签和工具提示&lt;/li>
&lt;li>若字段定义中不是必填，则可通过 PHP 代码仅对该子类设为必填&lt;/li>
&lt;/ul>
&lt;h2 id="必填字段的限制">必填字段的限制&lt;/h2>
&lt;p>某些属性类型不能设为必填：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>AttributeLinkedSet&lt;/strong>：可通过 PHP 代码强制必填&lt;/li>
&lt;li>&lt;strong>AttributeCaselog&lt;/strong>：仅对第一个条目有效，之后不再为空&lt;/li>
&lt;/ul>
&lt;h2 id="更改属性类型">更改属性类型&lt;/h2>
&lt;p>在已有对象的情况下更改属性类型&lt;strong>并非安全操作&lt;/strong>，取决于 MySQL/MariaDB 的能力：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>操作&lt;/th>
&lt;th>结果&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>增大 Text 字段大小&lt;/td>
&lt;td>支持，但 Setup 期间可能耗时&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>减小 Text 字段大小&lt;/td>
&lt;td>可能导致数据截断损坏&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Date 改为 DateTime&lt;/td>
&lt;td>时间部分设为 00:00:00&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Text 改为 HTML&lt;/td>
&lt;td>建议添加 &lt;code>&amp;lt;format&amp;gt;html&amp;lt;/format&amp;gt;&lt;/code> 标签而非更改类型&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Duration/Integer/Decimal/Date/Datetime 改为 String&lt;/td>
&lt;td>可能可行&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>String 改为 Duration/Integer/Decimal/Date/Datetime&lt;/td>
&lt;td>假设数据格式正确才可能可行&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>LinkedSetIndirect 改为 LinkedSet&lt;/td>
&lt;td>对数据库无影响，可安全回退&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="门户限制">门户限制&lt;/h2>
&lt;p>以下属性类型在门户中不可编辑：&lt;/p>
&lt;ul>
&lt;li>EnumSet 和 TagSet&lt;/li>
&lt;li>File 和 Image&lt;/li>
&lt;li>Duration&lt;/li>
&lt;/ul>
&lt;h2 id="关系中的属性限制">关系中的属性限制&lt;/h2>
&lt;p>链接类不支持以下字段类型：&lt;/p>
&lt;ul>
&lt;li>Caselog&lt;/li>
&lt;li>LinkedSet、LinkedSetIndirect&lt;/li>
&lt;li>Text、HTML、Template&lt;/li>
&lt;li>File、Image&lt;/li>
&lt;li>Duration&lt;/li>
&lt;li>TagSet、EnumSet&lt;/li>
&lt;/ul>
&lt;h2 id="属性类型选择">属性类型选择&lt;/h2>
&lt;h3 id="多值选择">多值选择&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>TagSet、EnumSet、LinkedSetIndirect&lt;/strong>：允许为单个对象字段设置多个值&lt;/li>
&lt;/ul>
&lt;h3 id="单值选择">单值选择&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Enum 或 ExternalKey&lt;/strong>（指向 Typology 子类）：允许选择单个值&lt;/li>
&lt;/ul>
&lt;h3 id="数据模型值-vs-数据库值">数据模型值 vs 数据库值&lt;/h3>
&lt;p>&lt;strong>Enum 和 EnumSet&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>缺点：添加新值需要 Designer MTP 或新扩展版本加 Setup&lt;/li>
&lt;li>优点：OQL 过滤器可基于这些值，不依赖实例数据&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Typology、TagSet 和 LinkedSetIndirect&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>优点：添加值快速简单&lt;/li>
&lt;li>缺点：基于这些值的 PHP 业务规则与数据耦合，文档化不足&lt;/li>
&lt;/ul>
&lt;h2 id="更改枚举值">更改枚举值&lt;/h2>
&lt;p>若在数据模型中更改 Enum 属性的允许值，而 iTop 中已有对象使用旧值：&lt;/p>
&lt;ul>
&lt;li>数据模型视角的允许值限制为新值集合&lt;/li>
&lt;li>每次 Setup 时，数据库视角的允许值 = 数据模型值 + 数据库中现有值&lt;/li>
&lt;li>编辑时，可选值 = 当前值 + 所有数据模型定义值&lt;/li>
&lt;li>搜索时，可选值仅限于数据模型定义值&lt;/li>
&lt;/ul>
&lt;h2 id="过滤关系">过滤关系&lt;/h2>
&lt;h3 id="外部键">外部键&lt;/h3>
&lt;p>&lt;code>AttributeExternalKey&lt;/code> 的 &lt;code>filter&lt;/code> XML 标签允许使用 OQL 查询过滤允许值。支持 &lt;code>$this-&amp;gt;attcode&lt;/code> 语法，其中 &lt;code>attcode&lt;/code> 是当前类的有效字段 ID。&lt;/p>
&lt;h3 id="多对多关系">多对多关系&lt;/h3>
&lt;p>例如限制团队成员属于同一组织：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>类&lt;/th>
&lt;th>Person&lt;/th>
&lt;th>lnkPersonToTeam&lt;/th>
&lt;th>Team&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>字段&lt;/td>
&lt;td>teams_list&lt;/td>
&lt;td>person_id / team_id&lt;/td>
&lt;td>persons_list&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>属性类型&lt;/td>
&lt;td>LinkedSetIndirect&lt;/td>
&lt;td>ExternalKey&lt;/td>
&lt;td>LinkedSetIndirect&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>过滤方法&lt;/td>
&lt;td>Search Form Prefill&lt;/td>
&lt;td>XML filter&lt;/td>
&lt;td>XML filter&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:attribute-limitation">https://www.itophub.io/wiki/page?id=3_2_0:customization:attribute-limitation&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/attribute-limitation.txt · Last modified: 2026/06/10 17:31 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 添加 1:1 关系</title><link>/docs/customization/how-to/datamodel/one-to-one-relation/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/one-to-one-relation/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在两个类之间创建一对一关系。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:one-to-one-relation">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>iTop 没有专门的 1:1 关系字段类型，但可以通过以下方式实现：&lt;/p>
&lt;ul>
&lt;li>此方案仅为可选方案之一&lt;/li>
&lt;li>关系只能在一边编辑&lt;/li>
&lt;li>关系必须从两边可见&lt;/li>
&lt;/ul>
&lt;h2 id="两个类之间的-11-关系">两个类之间的 1:1 关系&lt;/h2>
&lt;p>以 Person 和 CompanyCar 为例：一个人只能有一辆公司车，一辆车只能分配给一个人。&lt;/p>
&lt;h3 id="声明两个外部键">声明两个外部键&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;companycar_id&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeExternalKey&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filter&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[SELECT CompanyCar AS cc WHERE cc.person_id = 0]]&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dependencies/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>companycar_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target_class&amp;gt;&lt;/span>CompanyCar&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;on_target_delete&amp;gt;&lt;/span>DEL_MANUAL&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/on_target_delete&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;allow_target_creation&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/allow_target_creation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;person_id&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeExternalKey&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filter/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dependencies/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>person_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target_class&amp;gt;&lt;/span>Person&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;on_target_delete&amp;gt;&lt;/span>DEL_MANUAL&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/on_target_delete&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;allow_target_creation&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/allow_target_creation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="强制键同步">强制键同步&lt;/h3>
&lt;p>使用事件监听器在写入后同步两个外部键：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AfterWriteOneToOneRelationKeys&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_AFTER_WRITE&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filters&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filter&amp;gt;&lt;/span>Person&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filter&amp;gt;&lt;/span>CompanyCar&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/filters&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;code&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[function(Combodo\iTop\Service\Events\EventData $oEventData)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $sCurrentClass = &amp;#39;Person&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $sKeyToCurrent = &amp;#39;person_id&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $sRemoteClass = &amp;#39;CompanyCar&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $sKeyToRemote = &amp;#39;companycar_id&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oObject = $oEventData-&amp;gt;Get(&amp;#39;object&amp;#39;);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> if (get_class($oObject) == $sCurrentClass) {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $aChanges = $oObject-&amp;gt;ListPreviousValuesForUpdatedAttributes();
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> if (($oEventData-&amp;gt;Get(&amp;#39;is_new&amp;#39;) || array_key_exists($sKeyToRemote, $aChanges))
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> &amp;amp;&amp;amp; ($oObject-&amp;gt;Get($sKeyToRemote) &amp;gt; 0)) {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oNewRemote = MetaModel::GetObject($sRemoteClass, $oObject-&amp;gt;Get($sKeyToRemote), false, true);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> if ($oNewRemote) {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oNewRemote-&amp;gt;Set($sKeyToCurrent, $oObject-&amp;gt;GetKey());
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oNewRemote-&amp;gt;DBUpdate();
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> if (!$oEventData-&amp;gt;Get(&amp;#39;is_new&amp;#39;) &amp;amp;&amp;amp; array_key_exists($sKeyToRemote, $aChanges)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> &amp;amp;&amp;amp; ($aChanges[$sKeyToRemote] &amp;gt; 0)) {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oOldRemote = MetaModel::GetObject($sRemoteClass, $aChanges[$sKeyToRemote], false, true);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> if ($oOldRemote) {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oOldRemote-&amp;gt;Set($sKeyToCurrent, 0);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oOldRemote-&amp;gt;DBUpdate();
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">}]]&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;OnDeleteOneToOneRelationKeys&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_BEFORE_DELETE&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filters&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filter&amp;gt;&lt;/span>Person&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filter&amp;gt;&lt;/span>CompanyCar&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/filters&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;code&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[function(Combodo\iTop\Service\Events\EventData $oEventData)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $sCurrentClass = &amp;#39;Person&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $sKeyToCurrent = &amp;#39;person_id&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $sRemoteClass = &amp;#39;CompanyCar&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $sKeyToRemote = &amp;#39;companycar_id&amp;#39;;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oObject = $oEventData-&amp;gt;Get(&amp;#39;object&amp;#39;);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> if ((get_class($oObject) == $sCurrentClass) &amp;amp;&amp;amp; ($oObject-&amp;gt;Get($sKeyToRemote) &amp;gt; 0)) {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oOldRemote = MetaModel::GetObject($sRemoteClass, $oObject-&amp;gt;Get($sKeyToRemote), false, true);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> if ($oOldRemote) {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oOldRemote-&amp;gt;Set($sKeyToCurrent, 0);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $oOldRemote-&amp;gt;DBUpdate();
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">}]]&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="防止在一边编辑">防止在一边编辑&lt;/h3>
&lt;p>为避免无限更新循环，锁定一边的编辑：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">evtSetInitialAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ForceInitialAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">OPT_ATT_HIDDEN&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">evtSetAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ForceAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;person_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">OPT_ATT_READONLY&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="允许抢占">允许&amp;quot;抢占&amp;quot;&lt;/h3>
&lt;p>若要将已分配的车辆重新分配给另一个驾驶员：&lt;/p>
&lt;ul>
&lt;li>修改过滤器允许抢占&lt;/li>
&lt;li>在更新前一个驾驶员时，需要避免无限循环&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:one-to-one-relation">https://www.itophub.io/wiki/page?id=3_2_0:customization:one-to-one-relation&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/one-to-one-relation.txt · Last modified: 2025/05/19 16:10 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 添加 n:n 关系</title><link>/docs/customization/how-to/datamodel/add-relation/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-relation/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在两个类之间创建多对多（n:n）关系。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-relation">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>本教程演示如何在两个类之间创建多对多关系。以 Person 和 Location 之间的关系为例，记录人员的认证级别和最后访问时间。&lt;/p>
&lt;p>iTop 中的多对多关系存储为带有特殊 XML 标签 &lt;code>&amp;lt;is_link&amp;gt;&lt;/code>（值为 1）的类，告诉 iTop 如何在界面、控制台和门户中处理此类。&lt;/p>
&lt;h2 id="限制">限制&lt;/h2>
&lt;p>创建链接类时，以下字段类型&lt;strong>不受支持&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>Caselog&lt;/li>
&lt;li>LinkedSet、LinkedSetIndirect&lt;/li>
&lt;li>Text、HTML、Template&lt;/li>
&lt;li>File、Image&lt;/li>
&lt;li>Duration&lt;/li>
&lt;li>TagSet、EnumSet&lt;/li>
&lt;/ul>
&lt;p>在以下场景中会出现问题：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>门户中&lt;/strong>：编辑包含这些属性的链接将始终失败&lt;/li>
&lt;li>&lt;strong>控制台中编辑宿主对象时&lt;/strong>：编辑包含这些属性的链接将始终失败&lt;/li>
&lt;li>&lt;strong>控制台中读取宿主对象时&lt;/strong>：弹出窗口中编辑链接支持大多数属性，但 File 和 Image 除外&lt;/li>
&lt;/ul>
&lt;h3 id="门户-managebrick">门户 ManageBrick&lt;/h3>
&lt;p>若在 ManageBrick 中显示 LinkedSetAttribute，将产生错误：&lt;/p>
&lt;pre tabindex="0">&lt;code>DataTables warning: table id=table-UserRequest - Ajax error.
&lt;/code>&lt;/pre>&lt;h2 id="链接类定义">链接类定义&lt;/h2>
&lt;h3 id="属性">属性&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>class id&lt;/strong>：命名约定以 &lt;code>lnk&lt;/code> 开头，后跟按字母顺序的第一个类名，然后 &lt;code>To&lt;/code>，最后第二个类名&lt;/li>
&lt;li>&lt;strong>parent&lt;/strong>：&lt;code>cmdbAbstractObject&lt;/code>&lt;/li>
&lt;li>&lt;strong>category&lt;/strong>：&lt;code>bizmodel&lt;/code>&lt;/li>
&lt;li>&lt;strong>db_table&lt;/strong>：iTop 约定使用小写的类名&lt;/li>
&lt;li>&lt;strong>naming 和 reconciliation&lt;/strong>：通常使用两个相关对象来命名和标识关系&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;lnkLocationToPerson&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;parent&amp;gt;&lt;/span>cmdbAbstractObject&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/parent&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;category&amp;gt;&lt;/span>bizmodel&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/category&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;abstract&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/abstract&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;db_table&amp;gt;&lt;/span>lnklocationtoperson&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/db_table&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_link&amp;gt;&lt;/span>1&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_link&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;naming&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attributes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;location_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;person_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attributes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/naming&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;reconciliation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attributes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;location_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;person_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attributes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/reconciliation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="字段">字段&lt;/h3>
&lt;p>链接类需要两个 &lt;code>AttributeExternalKey&lt;/code>：&lt;code>person_id&lt;/code> 和 &lt;code>location_id&lt;/code>。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;lnkLocationToPerson&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;location_id&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeExternalKey&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>location_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filter/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dependencies/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target_class&amp;gt;&lt;/span>Location&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;on_target_delete&amp;gt;&lt;/span>DEL_AUTO&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/on_target_delete&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;person_id&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeExternalKey&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>person_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filter/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dependencies/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target_class&amp;gt;&lt;/span>Person&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;on_target_delete&amp;gt;&lt;/span>DEL_AUTO&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/on_target_delete&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;accreditation&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeEnum&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>accreditation&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;default_value&amp;gt;&lt;/span>restricted&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/default_value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;restricted&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;code&amp;gt;&lt;/span>restricted&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;unrestricted&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;code&amp;gt;&lt;/span>unrestricted&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;display_style&amp;gt;&lt;/span>radio_horizontal&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/display_style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;last_visit&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeDate&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>last_visit&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="展示">展示&lt;/h3>
&lt;p>&lt;code>details&lt;/code> 和 &lt;code>list&lt;/code> 为必填，&lt;code>default_search&lt;/code> 和 &lt;code>search&lt;/code> 为可选。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;lnkLocationToPerson&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;list&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;location_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;person_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>20&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;accreditation&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>30&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;last_visit&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>40&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/list&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;col:col1&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;location_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;person_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>20&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;accreditation&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>30&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;last_visit&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&amp;lt;rank&amp;gt;&lt;/span>40&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="标签">标签&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;dictionaries&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dictionary&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;EN US&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entries&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:lnkLocationToPerson/Name&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[%2$s is a visitor of %1$s]]&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:lnkLocationToPerson/Attribute:person_id&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Visitor]]&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:lnkLocationToPerson/Attribute:location_id&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Location]]&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:lnkLocationToPerson/Attribute:accreditation&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Accreditation]]&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:lnkLocationToPerson/Attribute:last_visit&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Last visit]]&amp;gt;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entries&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dictionary&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dictionaries&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="唯一性规则">唯一性规则&lt;/h3>
&lt;p>若要求在特定 Person 和 Location 之间只能有一个链接：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;lnkLocationToPerson&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;uniqueness_rules&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rule&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;no_duplicate&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attributes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;person_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;location_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attributes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;filter/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;disabled&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/disabled&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_blocking&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_blocking&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rule&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/uniqueness_rules&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="远程类引用">远程类引用&lt;/h2>
&lt;h3 id="person-类">Person 类&lt;/h3>
&lt;p>在 Person 详情中显示授权位置：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;locations_list&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeLinkedSetIndirect&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;ext_key_to_remote&amp;gt;&lt;/span>location_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/ext_key_to_remote&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;ext_key_to_me&amp;gt;&lt;/span>person_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/ext_key_to_me&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;linked_class&amp;gt;&lt;/span>lnkLocationToPerson&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/linked_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;count_min&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/count_min&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;count_max&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/count_max&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;duplicates&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/duplicates&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;locations_list&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>200&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="location-类">Location 类&lt;/h3>
&lt;p>类似地在 Location 中显示授权访客：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;persons_list&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeLinkedSetIndirect&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;ext_key_to_remote&amp;gt;&lt;/span>person_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/ext_key_to_remote&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;ext_key_to_me&amp;gt;&lt;/span>location_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/ext_key_to_me&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;linked_class&amp;gt;&lt;/span>lnkLocationToPerson&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/linked_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;count_min&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/count_min&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;count_max&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/count_max&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;duplicates&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/duplicates&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="31-特殊显示">3.1 特殊显示&lt;/h3>
&lt;p>iTop 3.1.0+ 可以使用类似 TagSet 和 EnumSet 的 widget 显示多对多关系。将 &lt;code>display_style&lt;/code> 设置为 &lt;code>property&lt;/code>（默认值为 &lt;code>tab&lt;/code>）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;locations_list&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;display_style&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;force&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>property&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/display_style&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-relation">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-relation&lt;/a>&lt;/p>
&lt;p>2026/06/10 17:31 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/add-relation.txt · Last modified: 2026/06/10 17:31 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 添加保密属性</title><link>/docs/customization/how-to/datamodel/confidential-attribute/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/confidential-attribute/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在 iTop 中为特定对象添加保密属性，限制特定用户角色的读写访问。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:confidential-attribute">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="目标">目标&lt;/h2>
&lt;p>&lt;strong>需求：&lt;/strong> 特定对象上的某些信息需要对部分用户限制可见性。&lt;/p>
&lt;p>&lt;strong>约束：&lt;/strong> 目前 iTop 按类和组织全局控制读取访问，没有字段级别的选项。&lt;/p>
&lt;p>&lt;strong>方案：&lt;/strong> 本教程提供一种实现保密属性的方式：&lt;/p>
&lt;ul>
&lt;li>读取权限限制为具有特定角色的用户，其他用户只能看到 &lt;code>*&lt;/code>&lt;/li>
&lt;li>写入权限按角色分配&lt;/li>
&lt;li>保密属性可以是任意类型：成本、HTML 描述、图片、案例日志等&lt;/li>
&lt;/ul>
&lt;h2 id="设计概述">设计概述&lt;/h2>
&lt;p>为确保该字段不被未授权用户读取，我们将其放入一个独立的类中。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>注意：&lt;/strong> 基于当前用户隐藏对象详情中的字段是一种虚假的安全性。通过配置对象列表中显示的字段，任何人都可以获取该字段的值。&lt;/p>
&lt;/blockquote>
&lt;p>实现步骤：&lt;/p>
&lt;ol>
&lt;li>创建保密类&lt;/li>
&lt;li>更新宿主类&lt;/li>
&lt;li>建立一对一关系的连接&lt;/li>
&lt;/ol>
&lt;h2 id="保密类">保密类&lt;/h2>
&lt;p>这个新类只包含：&lt;/p>
&lt;ul>
&lt;li>一个硬编码的友好名称 &lt;code>******&lt;/code>&lt;/li>
&lt;li>一个 &lt;code>value&lt;/code> 字段，类型对应需要存储的保密值&lt;/li>
&lt;li>一个指向宿主类的外部键（宿主类本应包含该保密属性）&lt;/li>
&lt;/ul>
&lt;p>该类必须设置 &lt;code>category = grant_by_profile, application&lt;/code>：&lt;/p>
&lt;ul>
&lt;li>&lt;code>grant_by_profile&lt;/code> 允许控制谁可以看到它。需要创建一个包含此新类的组，以及包含该组的配置文件&lt;/li>
&lt;li>&lt;code>application&lt;/code> 将其从 &amp;ldquo;所有类&amp;rdquo; 组提供的读取访问中移除&lt;/li>
&lt;/ul>
&lt;p>定义一个摘要卡片，显示 &amp;ldquo;value&amp;rdquo; 和宿主对象的友好名称。&lt;/p>
&lt;p>可以放在任何模块中，但放在宿主类所在的模块更合理。&lt;/p>
&lt;ul>
&lt;li>防止从保密属性类编辑外部键 → 设为只读（2 个事件）&lt;/li>
&lt;li>当不存在外部键时，通过 CheckToWrite 阻止创建此类对象（事件）&lt;/li>
&lt;li>从表单中隐藏该字段，但将 &lt;code>host_id_friendlyname&lt;/code> 放入表单以帮助记住正在修改的内容&lt;/li>
&lt;/ul>
&lt;h2 id="宿主类">宿主类&lt;/h2>
&lt;p>创建一个指向新创建类的外部键：&lt;/p>
&lt;ul>
&lt;li>添加过滤器，只列出未分配的保密属性（实际上避免提供任何已有项）&lt;/li>
&lt;li>确保 AfterWrite → 更新保密属性的外部键&lt;/li>
&lt;li>当外部键 != 0 时阻止编辑，但仍可以更改其内容&lt;/li>
&lt;/ul>
&lt;p>在保密类上创建一个 LinkedSet 属性，使用外部键 &lt;code>host_id&lt;/code>，并将其显示为 &amp;ldquo;properties&amp;rdquo;。&lt;/p>
&lt;h2 id="同步键">同步键&lt;/h2>
&lt;p>参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:one-to-one-relation">添加 1:1 关系&lt;/a>。&lt;/p>
&lt;h2 id="局限性">局限性&lt;/h2>
&lt;ul>
&lt;li>无法阻止保密属性的纯创建，可能导致孤儿值&lt;/li>
&lt;li>无法在弹出窗口中编辑属性&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:confidential-attribute">https://www.itophub.io/wiki/page?id=3_2_0:customization:confidential-attribute&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/confidential-attribute.txt · Last modified: 2025/05/20 12:39 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 添加状态和转换</title><link>/docs/customization/how-to/datamodel/add-state-transition/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-state-transition/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何为 UserRequest 添加新状态和转换，以标识等待第三方提供商的状态。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-state-transition">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>本教程将：&lt;/p>
&lt;ul>
&lt;li>为 UserRequest 添加新状态，表示等待第三方提供商&lt;/li>
&lt;li>添加新事件，将用户请求移入该新状态&lt;/li>
&lt;li>添加两个转换，允许工单移入和移出此状态&lt;/li>
&lt;li>为需要执行此转换的用户启用访问权限&lt;/li>
&lt;/ul>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;h3 id="创建新状态">创建新状态&lt;/h3>
&lt;ol>
&lt;li>点击工具栏的 &lt;strong>Add State&lt;/strong> 按钮&lt;/li>
&lt;li>填写必填属性并点击 &lt;strong>Create State&lt;/strong>&lt;/li>
&lt;/ol>
&lt;h3 id="添加事件">添加事件&lt;/h3>
&lt;ol>
&lt;li>点击 Events 标题旁的小按钮&lt;/li>
&lt;li>事件代码按约定命名为 &lt;code>ev_xxxx&lt;/code>，如 &lt;code>ev_pending_provider&lt;/code>&lt;/li>
&lt;li>类型选择 &lt;strong>End User action&lt;/strong>（用户界面中可提议的转换）&lt;/li>
&lt;li>事件的标签将应用于所有使用该事件的转换&lt;/li>
&lt;/ol>
&lt;h3 id="添加转换">添加转换&lt;/h3>
&lt;ol>
&lt;li>点击工具栏按钮或右键状态选择 &lt;strong>New Transition&lt;/strong>&lt;/li>
&lt;li>选择起始状态、事件和目标状态&lt;/li>
&lt;li>点击 OK 创建新转换&lt;/li>
&lt;/ol>
&lt;h3 id="启用访问权限">启用访问权限&lt;/h3>
&lt;p>为 Support Agent 配置文件启用此权限：&lt;/p>
&lt;ol>
&lt;li>导航到 &lt;strong>User Rights&lt;/strong> 主标签页&lt;/li>
&lt;li>点击 &lt;strong>Profiles&lt;/strong> 子标签页&lt;/li>
&lt;li>选择 &lt;strong>Support Agent&lt;/strong> 配置文件&lt;/li>
&lt;li>在 UserRequest 前点击编辑图标&lt;/li>
&lt;li>找到 &lt;code>ev_pending_provider&lt;/code> 事件，将权限从 Undefined 改为 Allow&lt;/li>
&lt;/ol>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="声明新状态">声明新状态&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;!-- 向现有 status 添加新状态值 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;status&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;value&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;pending_provider&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;code&amp;gt;&lt;/span>pending_provider&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/values&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>添加字典条目：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:UserRequest/Attribute:status/Value:pending_provider&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Pending provider]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加事件刺激">添加事件（刺激）&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;stimuli&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;stimulus&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_pending_provider&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;StimulusUserAction&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/stimuli&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:UserRequest/Stimulus:ev_pending_provider&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Wait for Provider]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加转换-1">添加转换&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;assigned&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transition&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_pending_provider&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;stimulus&amp;gt;&lt;/span>ev_pending_provider&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/stimulus&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target&amp;gt;&lt;/span>pending_provider&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;pending_provider&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transition&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_assign&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;stimulus&amp;gt;&lt;/span>ev_assign&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/stimulus&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target&amp;gt;&lt;/span>assigned&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;inherit_flags_from&amp;gt;&lt;/span>assigned&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/inherit_flags_from&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="启用访问权限-1">启用访问权限&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;profile&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;5&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;groups&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;group&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;UserRequest&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_pending_provider&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/group&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/groups&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/profile&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-state-transition">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-state-transition&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/add-state-transition.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 统计在某状态中花费的时间</title><link>/docs/customization/how-to/datamodel/add-state/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-state/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何使用秒表属性统计工单在特定状态中花费的时间。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-state">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>本教程统计每张工单等待第三方提供商的时间。需要：&lt;/p>
&lt;ul>
&lt;li>在 UserRequest 类上添加秒表属性，在 &lt;code>pending_provider&lt;/code> 状态时计时&lt;/li>
&lt;li>添加子项字段显示等待提供商的时间&lt;/li>
&lt;li>仅在 UserRequest 的某些状态中显示总等待时间&lt;/li>
&lt;/ul>
&lt;p>假设已&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-state-transition">添加 &amp;ldquo;pending_provider&amp;rdquo; 状态和 2 个转换&lt;/a>。&lt;/p>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;h3 id="添加秒表">添加秒表&lt;/h3>
&lt;ol>
&lt;li>点击 Stopwatches 标题旁的小按钮&lt;/li>
&lt;li>填写代码、标签，选择状态 &lt;code>pending_provider&lt;/code>&lt;/li>
&lt;/ol>
&lt;h3 id="追踪时间">追踪时间&lt;/h3>
&lt;ol>
&lt;li>创建新字段，类型选择 &lt;strong>Stopwatch Value&lt;/strong>&lt;/li>
&lt;li>选择秒表，值选择 &lt;strong>Total time spent&lt;/strong>&lt;/li>
&lt;/ol>
&lt;h3 id="显示秒表">显示秒表&lt;/h3>
&lt;p>将字段添加到展示/详情视图中。在 Schema 标签页中，在秒表不相关的状态中隐藏此字段。&lt;/p>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="添加秒表-1">添加秒表&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;providerstopwatch&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeStopWatch&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;pending_provider&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>pending_provider&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;working_time/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;thresholds/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;always_load_in_tables&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/always_load_in_tables&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:UserRequest/Attribute:providerstopwatch&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Provider stopwatch]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="追踪时间-1">追踪时间&lt;/h3>
&lt;p>此步骤&lt;strong>必须&lt;/strong>执行，才能在表单中显示或通过 OQL 查询：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;pending_provider_delay&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeSubItem&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target_attcode&amp;gt;&lt;/span>providerstopwatch&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target_attcode&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item_code&amp;gt;&lt;/span>timespent&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item_code&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>可用子项代码：&lt;code>timespent&lt;/code>、&lt;code>started&lt;/code>、&lt;code>laststart&lt;/code>、&lt;code>stopped&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:UserRequest/Attribute:pending_provider_delay&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Provider time spent]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="显示秒表-1">显示秒表&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;col:col1&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;fieldset:Ticket:moreinfo&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;pending_provider_delay&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>80&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;providerstopwatch&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>90&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="按状态控制显示">按状态控制显示&lt;/h3>
&lt;ul>
&lt;li>在 &lt;code>new&lt;/code> 状态中隐藏 &lt;code>pending_provider_delay&lt;/code>（会传播到所有链式状态）&lt;/li>
&lt;li>在 &lt;code>resolved&lt;/code> 状态中设为只读&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;lifecycle&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;new&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;pending_provider_delay&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;hidden/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/flags&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;resolved&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;pending_provider_delay&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;read_only/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/flags&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/lifecycle&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="秒表行为">秒表行为&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>从未启动&lt;/strong>：所有子项为空&lt;/li>
&lt;li>&lt;strong>首次进入 pending_provider&lt;/strong>：秒表运行中，Elapsed 不可用，Started 和 LastStart 相等&lt;/li>
&lt;li>&lt;strong>首次返回 assigned&lt;/strong>：秒表停止，Elapsed 可用，Stopped 有记录&lt;/li>
&lt;li>&lt;strong>再次进入 pending_provider&lt;/strong>：秒表重新运行，Started 不变，LastStart 更新&lt;/li>
&lt;li>&lt;strong>再次返回 assigned&lt;/strong>：秒表停止，Elapsed 累计，注意不等于 Started 和 Stopped 的差值&lt;/li>
&lt;/ol>
&lt;p>秒表自动计算，用户不可编辑。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-state">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-state&lt;/a>&lt;/p>
&lt;p>Last modified: 2024/09/10 10:25 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/add-state.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 委派管理员工具菜单</title><link>/docs/customization/how-to/datamodel/delegate-rights/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/delegate-rights/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何将 &amp;ldquo;管理员工具&amp;rdquo; 菜单委派给非管理员用户。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:delegate_rights">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>从 iTop 2.5 开始，可以将管理员工具菜单授予非管理员用户。&lt;/p>
&lt;h2 id="限制">限制&lt;/h2>
&lt;p>以下菜单&lt;strong>不能&lt;/strong>委派给非管理员：&lt;/p>
&lt;ul>
&lt;li>Schedule Backup&lt;/li>
&lt;li>Log Management（除非使用 Log Management 2.0.1+）&lt;/li>
&lt;li>iTop Hub&lt;/li>
&lt;/ul>
&lt;p>某些类（如历史相关类）没有组织，因此向具有 &amp;ldquo;Allowed Organizations&amp;rdquo; 的用户提供 &amp;ldquo;Run Query&amp;rdquo; 访问权限会产生安全漏洞。&lt;/p>
&lt;h2 id="菜单可见性">菜单可见性&lt;/h2>
&lt;p>从 XML 1.5 版本开始，可以基于类和操作权限控制任何菜单的访问。只有具有该类操作权限的人才能看到该菜单。&lt;/p>
&lt;p>默认由类操作控制的管理菜单：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>菜单&lt;/th>
&lt;th>控制类&lt;/th>
&lt;th>操作&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Users&lt;/td>
&lt;td>User&lt;/td>
&lt;td>write&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Profile&lt;/td>
&lt;td>Profile&lt;/td>
&lt;td>write&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Notifications&lt;/td>
&lt;td>Trigger&lt;/td>
&lt;td>write&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Audit&lt;/td>
&lt;td>AuditCategory&lt;/td>
&lt;td>write&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Run Query&lt;/td>
&lt;td>ResourceRunQueriesMenu&lt;/td>
&lt;td>write&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Query phrasebook&lt;/td>
&lt;td>Query&lt;/td>
&lt;td>write&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Export&lt;/td>
&lt;td>ResourceAdminMenu&lt;/td>
&lt;td>write&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Data Model&lt;/td>
&lt;td>ResourceRunQueriesMenu&lt;/td>
&lt;td>write&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Universal Search&lt;/td>
&lt;td>ResourceAdminMenu&lt;/td>
&lt;td>write&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Synchronization Data Sources&lt;/td>
&lt;td>SynchroDataSource&lt;/td>
&lt;td>write&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>预定义组：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>组 ID&lt;/th>
&lt;th>默认包含菜单&lt;/th>
&lt;th>包含类&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>User&lt;/td>
&lt;td>用户账户、配置文件&lt;/td>
&lt;td>User、URP_UserOrg、URP_UserProfile、URP_Profiles&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Audit&lt;/td>
&lt;td>审计、运行查询&lt;/td>
&lt;td>AuditCategory、AuditRule、ResourceRunQueriesMenu&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Notification&lt;/td>
&lt;td>通知、运行查询&lt;/td>
&lt;td>Trigger、Action、lnkTriggerAction、ResourceRunQueriesMenu&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Query&lt;/td>
&lt;td>查询短语手册、运行查询&lt;/td>
&lt;td>Query、QueryOQL、ResourceRunQueriesMenu&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>SynchroData&lt;/td>
&lt;td>同步数据源&lt;/td>
&lt;td>SynchroDataSource&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>LogManagement&lt;/td>
&lt;td>日志中心&lt;/td>
&lt;td>ResourceLogMenu&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>AdminTools&lt;/td>
&lt;td>所有上述菜单&lt;/td>
&lt;td>所有上述类&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="分步示例">分步示例&lt;/h2>
&lt;p>将 &amp;ldquo;Export Menu&amp;rdquo; 委派给 &amp;ldquo;Config Manager&amp;rdquo; 配置文件：&lt;/p>
&lt;h3 id="创建抽象类">创建抽象类&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;RessourceExportMenu&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;parent&amp;gt;&lt;/span>AbstractResource&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/parent&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;comment&amp;gt;&lt;/span>/* Export Menu access control. */&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/comment&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;abstract&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/abstract&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;category&amp;gt;&lt;/span>grant_by_profile&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/category&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;methods/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="覆盖菜单定义">覆盖菜单定义&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;menu&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ExportMenu&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;WebPageMenuNode&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;enable_class&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redefine&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>RessourceExportMenu&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/enable_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;enable_action&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redefine&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>UR_ACTION_MODIFY&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/enable_action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/menu&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="完成组和配置文件定义">完成组和配置文件定义&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;user_rights&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;groups&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;group&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Export&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;classes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;RessourceExportMenu&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/classes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/group&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/groups&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;profiles&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;profile&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;3&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;groups&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;group&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Export&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;action:write&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>allow&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/group&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/groups&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/profile&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/profiles&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/user_rights&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="可创建的配置文件">可创建的配置文件&lt;/h2>
&lt;p>以下是一些可创建的配置文件示例：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>User Manager&lt;/strong>（id=43）— 管理用户账户&lt;/li>
&lt;li>&lt;strong>Notification Manager&lt;/strong>（id=44）— 管理触发器和动作&lt;/li>
&lt;li>&lt;strong>Audit Manager&lt;/strong>（id=45）— 管理审计规则&lt;/li>
&lt;li>&lt;strong>Query Manager&lt;/strong>（id=46）— 管理查询短语手册&lt;/li>
&lt;li>&lt;strong>SynchroData Manager&lt;/strong>（id=47）— 管理同步数据源&lt;/li>
&lt;li>&lt;strong>Admin Tools Manager&lt;/strong>（id=48）— 管理所有管理工具&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:delegate_rights">https://www.itophub.io/wiki/page?id=3_2_0:customization:delegate_rights&lt;/a>&lt;/p>
&lt;p>2024/09/10 10:25 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/delegate_rights.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 为 Server 类添加字段</title><link>/docs/customization/how-to/datamodel/add-attribute-sample/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-attribute-sample/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何为现有 iTop 类添加新字段。这是学习创建 iTop 扩展的第一个入门教程。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-attribute-sample">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>本教程将逐步介绍如何为现有 iTop 对象添加新字段。以在 &lt;strong>Server&lt;/strong> 对象上添加一个文本字段为例。&lt;/p>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;p>Combodo 的 iTop Professional 或 Essential 客户无需创建扩展，可直接使用 ITSM Designer：&lt;/p>
&lt;ol>
&lt;li>从 iTop 导航到 ITSM Designer&lt;/li>
&lt;li>打开 &lt;strong>Classes&lt;/strong> 标签页，选择 &lt;strong>Server&lt;/strong> 类&lt;/li>
&lt;li>点击顶部工具栏的创建新字段图标&lt;/li>
&lt;li>选择属性类型，填写字段属性（包括标签）&lt;/li>
&lt;li>切换到 &lt;strong>Presentation&lt;/strong> 标签页的 &lt;strong>Details view&lt;/strong>，拖拽新字段到所需位置&lt;/li>
&lt;li>点击 &lt;strong>Move To Production&lt;/strong> 按钮推送更改&lt;/li>
&lt;/ol>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="准备工作">准备工作&lt;/h3>
&lt;ul>
&lt;li>在开发机器上安装 iTop&lt;/li>
&lt;li>支持 UTF-8 的文本编辑器（Windows 可用 Wordpad、PSPad 或 Notepad++）&lt;/li>
&lt;/ul>
&lt;h3 id="定制流程">定制流程&lt;/h3>
&lt;ol>
&lt;li>安装 iTop 开发实例&lt;/li>
&lt;li>安装 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">工具包&lt;/a> 辅助定制&lt;/li>
&lt;li>使用&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">扩展创建向导&lt;/a>创建空模块&lt;/li>
&lt;li>将模块复制到 &lt;code>extensions&lt;/code> 文件夹并运行安装&lt;/li>
&lt;li>修改模块并使用工具包验证&lt;/li>
&lt;/ol>
&lt;h3 id="创建模块">创建模块&lt;/h3>
&lt;p>使用扩展创建向导，填写以下信息：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>标签&lt;/th>
&lt;th>值&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>模块名称&lt;/td>
&lt;td>sample-add-attribute&lt;/td>
&lt;td>以 &lt;code>itop-&lt;/code> 和 &lt;code>combodo-&lt;/code> 开头的名称保留给 Combodo 使用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>模块标签&lt;/td>
&lt;td>Add Attribute Sample&lt;/td>
&lt;td>安装向导中显示的标签&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>模块版本&lt;/td>
&lt;td>1.0.0&lt;/td>
&lt;td>使用 X.Y.Z 三位版本号&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>类别&lt;/td>
&lt;td>business&lt;/td>
&lt;td>修改数据模型的模块应使用 &amp;lsquo;business&amp;rsquo; 类别&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>依赖&lt;/td>
&lt;td>itop-config-mgmt/2.0.0&lt;/td>
&lt;td>依赖 iTop 配置管理模块&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="安装空模块">安装空模块&lt;/h3>
&lt;p>将 zip 文件解压到 &lt;code>extensions&lt;/code> 文件夹，运行 &lt;code>http://your_itop/setup/&lt;/code> 重新安装，选择 &lt;strong>Update an existing instance&lt;/strong>。&lt;/p>
&lt;h3 id="添加字段">添加字段&lt;/h3>
&lt;p>编辑 &lt;code>datamodel.sample-add-attribute.xml&lt;/code>，在 &lt;code>&amp;lt;classes&amp;gt;&lt;/code> 标签内添加：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Server&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;if_exists&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;notes&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeText&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>notes&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;default_value/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用工具包验证后，点击 &lt;strong>Update iTop Code&lt;/strong> 应用更改。此时数据库已添加新列，但界面尚未显示。&lt;/p>
&lt;h3 id="使字段可见">使字段可见&lt;/h3>
&lt;p>将新字段添加到 Server 的详情展示中。编辑 XML 文件，在 &lt;code>&amp;lt;presentation&amp;gt;&lt;/code> 中重新定义 &lt;code>details&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redefine&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;!-- ... 现有字段 ... --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;col:col2&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;fieldset:Server:otherinfo&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>30&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;notes&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>40&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加字段标签">添加字段标签&lt;/h3>
&lt;p>编辑 &lt;code>en.dict.sample-add-attribute.php&lt;/code>，添加字典条目：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">Dict&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">Add&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;EN US&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;English&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;English&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;Class:Server/Attribute:notes&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;Additional Notes&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="高级方案">高级方案&lt;/h3>
&lt;p>为避免与其他扩展冲突，可以不重新定义整个 &lt;code>details&lt;/code>，而是精确定位插入点：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;col:col2&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;fieldset:Server:otherinfo&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;notes&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>40&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="部署">部署&lt;/h2>
&lt;p>将模块文件夹复制到目标 iTop 的 &lt;code>extensions&lt;/code> 目录并运行安装。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-attribute-sample">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-attribute-sample&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/add-attribute-sample.txt · Last modified: 2026/03/16 14:06 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 为类添加生命周期</title><link>/docs/customization/how-to/datamodel/add-lifecycle/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-lifecycle/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何为 PhysicalDevice 类添加简单的生命周期。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-lifecycle">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>本教程演示如何为 PhysicalDevice 添加生命周期，使用现有的状态值并定义状态间的转换。&lt;/p>
&lt;p>需要：&lt;/p>
&lt;ul>
&lt;li>确定承载生命周期状态的枚举属性（若不存在则创建）&lt;/li>
&lt;li>定义默认状态（对象创建时自动使用）&lt;/li>
&lt;li>定义不同的状态和刺激事件&lt;/li>
&lt;li>为每个状态定义：前一个状态（作为字段标志的基础）、可用的转换、字段的必填/只读/隐藏标志&lt;/li>
&lt;/ul>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;ol>
&lt;li>选择类，进入 &lt;strong>Lifecycle&lt;/strong> 标签页，点击 &lt;strong>Add State&lt;/strong> 图标&lt;/li>
&lt;li>选择用于存储生命周期状态的&lt;strong>枚举字段&lt;/strong>&lt;/li>
&lt;li>点击 &lt;strong>Initialize&lt;/strong>，枚举字段的现有值将被创建为状态&lt;/li>
&lt;li>若枚举有默认值，则作为&lt;strong>初始状态&lt;/strong>；否则第一个值被使用（可随时修改）&lt;/li>
&lt;/ol>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="数据模型">数据模型&lt;/h3>
&lt;p>PhysicalDevice 已有 &lt;code>status&lt;/code> 枚举字段可用于承载生命周期。假设管理 4 个状态：implementation、production、obsolete、stock。标准数据模型中 CI 创建时状态为 production，这里改为 implementation：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;PhysicalDevice&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;status&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;default_value&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redefine&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>implementation&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/default_value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="生命周期定义">生命周期定义&lt;/h3>
&lt;p>添加生命周期标签、状态字段和状态列表：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;PhysicalDevice&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;lifecycle&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&amp;gt;&lt;/span>status&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;stimuli&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;stimulus&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_move2prod&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;StimulusUserAction&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;stimulus&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_obsolete&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;StimulusUserAction&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;stimulus&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_stock&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;StimulusUserAction&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/stimuli&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;implementation&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transition&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_move2prod&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;stimulus&amp;gt;&lt;/span>ev_move2prod&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/stimulus&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target&amp;gt;&lt;/span>production&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;production&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transition&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_obsolete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target&amp;gt;&lt;/span>obsolete&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transition&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_stock&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target&amp;gt;&lt;/span>stock&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;obsolete&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transitions/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;stock&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transition&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_move2prod&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;stimulus&amp;gt;&lt;/span>ev_move2prod&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/stimulus&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;target&amp;gt;&lt;/span>production&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/target&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/lifecycle&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>状态转换图：&lt;/p>
&lt;pre tabindex="0">&lt;code>implementation --ev_move2prod--&amp;gt; production --ev_stock--&amp;gt; stock
|
+--ev_obsolete--&amp;gt; obsolete
&lt;/code>&lt;/pre>&lt;p>有关生命周期的更多可能性，请参阅 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">XML 数据模型参考&lt;/a>。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-lifecycle">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-lifecycle&lt;/a>&lt;/p>
&lt;p>2024/09/10 10:25 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/add-lifecycle.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 新的认证方式</title><link>/docs/customization/how-to/datamodel/authentication/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/authentication/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍 iTop 2.7+ 的认证流程以及如何通过扩展添加新的认证方式。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:authentication">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>从 iTop 2.7.0 开始，添加新的认证方式变得更加容易。本文档介绍：&lt;/p>
&lt;ul>
&lt;li>iTop 2.7 的登录流程&lt;/li>
&lt;li>扩展登录流程的新接口（API）&lt;/li>
&lt;li>如何扩展认证流程&lt;/li>
&lt;/ul>
&lt;h2 id="认证行为">认证行为&lt;/h2>
&lt;p>iTop 2.7 的认证流程使用 FSM（有限状态机）。&lt;/p>
&lt;h3 id="通用算法">通用算法&lt;/h3>
&lt;ul>
&lt;li>自动机从 &lt;code>start&lt;/code> 状态开始&lt;/li>
&lt;li>对每个状态调用所有相关插件&lt;/li>
&lt;li>当所有插件都接受继续时，自动机进入下一个状态&lt;/li>
&lt;/ul>
&lt;h3 id="登录状态">登录状态&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>状态&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>start&lt;/td>
&lt;td>入口状态，首次调用或错误/注销后&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>login mode detection&lt;/td>
&lt;td>检测使用哪个登录插件&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>read credentials&lt;/td>
&lt;td>读取凭据，显示表单或重定向到外部认证系统&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>check credentials&lt;/td>
&lt;td>验证凭据是否有效&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>credentials ok&lt;/td>
&lt;td>验证凭据对应有效的 iTop 用户&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>user ok&lt;/td>
&lt;td>额外用户检查，如双因素认证&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>connected&lt;/td>
&lt;td>用户已连接&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>error&lt;/td>
&lt;td>发生错误，下一个状态为 start&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="主要变量">主要变量&lt;/h3>
&lt;ul>
&lt;li>&lt;code>$_SESSION['login_state']&lt;/code> — 当前状态&lt;/li>
&lt;li>&lt;code>$_SESSION['login_mode']&lt;/code> — 登录模式&lt;/li>
&lt;li>&lt;code>$_SESSION['can_logoff']&lt;/code> — 是否允许注销&lt;/li>
&lt;/ul>
&lt;h2 id="认证接口">认证接口&lt;/h2>
&lt;h3 id="iloginfsmextension">iLoginFSMExtension&lt;/h3>
&lt;p>低级插件接口，包含两个方法：&lt;/p>
&lt;ul>
&lt;li>&lt;code>ListSupportedLoginModes()&lt;/code> — 返回支持的登录模式数组&lt;/li>
&lt;li>&lt;code>LoginAction($sLoginState, &amp;amp;$iErrorCode)&lt;/code> — 每个状态调用&lt;/li>
&lt;/ul>
&lt;p>返回值：&lt;/p>
&lt;ul>
&lt;li>&lt;code>LOGIN_FSM_RETURN_ERROR&lt;/code> — 发生错误&lt;/li>
&lt;li>&lt;code>LOGIN_FSM_RETURN_OK&lt;/code> — 登录成功，流程终止&lt;/li>
&lt;li>&lt;code>LOGIN_FSM_RETURN_IGNORE&lt;/code> — 继续到下一个插件或状态&lt;/li>
&lt;/ul>
&lt;h3 id="abstractloginfsmextension">AbstractLoginFSMExtension&lt;/h3>
&lt;p>抽象类，实现 &lt;code>iLoginFSMExtension&lt;/code> 并为每个状态提供回调函数：&lt;/p>
&lt;ul>
&lt;li>&lt;code>OnStart(&amp;amp;$iErrorCode)&lt;/code>&lt;/li>
&lt;li>&lt;code>OnModeDetection(&amp;amp;$iErrorCode)&lt;/code>&lt;/li>
&lt;li>&lt;code>OnReadCredentials(&amp;amp;$iErrorCode)&lt;/code>&lt;/li>
&lt;li>&lt;code>OnCheckCredentials(&amp;amp;$iErrorCode)&lt;/code>&lt;/li>
&lt;li>&lt;code>OnCredentialsOK(&amp;amp;$iErrorCode)&lt;/code>&lt;/li>
&lt;li>&lt;code>OnUsersOK(&amp;amp;$iErrorCode)&lt;/code>&lt;/li>
&lt;li>&lt;code>OnConnected(&amp;amp;$iErrorCode)&lt;/code>&lt;/li>
&lt;li>&lt;code>OnError(&amp;amp;$iErrorCode)&lt;/code>&lt;/li>
&lt;/ul>
&lt;h3 id="ilogoutextension">iLogoutExtension&lt;/h3>
&lt;p>用户注销时调用。&lt;/p>
&lt;ul>
&lt;li>&lt;code>ListSupportedLoginModes()&lt;/code> — 返回支持的登录模式&lt;/li>
&lt;li>&lt;code>LogoutAction()&lt;/code> — 用户注销时调用&lt;/li>
&lt;/ul>
&lt;h2 id="扩展认证流程">扩展认证流程&lt;/h2>
&lt;p>要添加新的认证方式：&lt;/p>
&lt;ol>
&lt;li>提供扩展 &lt;code>AbstractLoginFSMExtension&lt;/code>（推荐）或实现 &lt;code>iLoginFSMExtension&lt;/code> 的 PHP 类&lt;/li>
&lt;li>可选：提供实现 &lt;code>iLogoutExtension&lt;/code> 的 PHP 类&lt;/li>
&lt;li>在 &lt;code>allowed_login_types&lt;/code> 配置中注册新模式&lt;/li>
&lt;/ol>
&lt;h3 id="登录-api">登录 API&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">// 验证凭据对应有效用户
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">static&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">LoginWebPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">CheckUser&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sAuthUser&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sAuthPassword&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sAuthentication&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;external&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">// 登录成功时存储用户信息到会话
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">static&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">LoginWebPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">OnLoginSuccess&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sAuthUser&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sAuthentication&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sLoginMode&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">// 检查已登录用户是否仍然有效
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">static&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">LoginWebPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">CheckLoggedUser&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&lt;/span>&lt;span style="color:#000">$iErrorCode&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="用户预配">用户预配&lt;/h3>
&lt;p>在 &lt;code>AbstractLoginFSMExtension::OnCheckCredentials()&lt;/code> 中创建用户和人员：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">private&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">DoUserProvisioning&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sLogin&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sEmail&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sFirstName&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sLastName&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sOrganization&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$aProfiles&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">!&lt;/span>&lt;span style="color:#000">Config&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;synchronize_user&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">try&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">LoginWebPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">FindUser&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sLogin&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">false&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span> &lt;span style="color:#8f5902;font-style:italic">// 用户已存在
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oPerson&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">LoginWebPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">FindPerson&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sEmail&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oPerson&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#204a87;font-weight:bold">null&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">!&lt;/span>&lt;span style="color:#000">Config&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;synchronize_contact&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oPerson&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">LoginWebPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">ProvisionPerson&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sFirstName&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sLastName&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sEmail&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$sOrganization&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">LoginWebPage&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">ProvisionUser&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sLogin&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$oPerson&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$aProfiles&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span> &lt;span style="color:#204a87;font-weight:bold">catch&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Exception&lt;/span> &lt;span style="color:#000">$e&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">IssueLog&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">Error&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$e&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">getMessage&lt;/span>&lt;span style="color:#000;font-weight:bold">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="示例cas-认证">示例：CAS 认证&lt;/h3>
&lt;p>&lt;code>authent-cas&lt;/code> 模块实现 CAS 认证，包含 &lt;code>CASLoginExtension&lt;/code> 类：&lt;/p>
&lt;ul>
&lt;li>&lt;code>ListSupportedLoginModes()&lt;/code> — 返回 &lt;code>['cas']&lt;/code>&lt;/li>
&lt;li>&lt;code>OnReadCredentials()&lt;/code> — 重定向到 CAS 服务器认证&lt;/li>
&lt;li>&lt;code>OnCheckCredentials()&lt;/code> — 检查凭据并预配用户&lt;/li>
&lt;li>&lt;code>OnCredentialsOK()&lt;/code> — 验证 iTop 用户有效性&lt;/li>
&lt;li>&lt;code>OnConnected()&lt;/code> — 检查用户仍然有效&lt;/li>
&lt;li>&lt;code>LogoutAction()&lt;/code> — 同时从 CAS 服务器注销&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:authentication">https://www.itophub.io/wiki/page?id=3_2_0:customization:authentication&lt;/a>&lt;/p>
&lt;p>2024/09/10 10:25 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/authentication.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 用户保护</title><link>/docs/customization/how-to/datamodel/user-protection/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/user-protection/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何防止因修改人员组织而导致用户意外被禁用。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:user-protection">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>若用户定义了 &amp;ldquo;Allowed organizations&amp;rdquo; 并关联到 Person，则该 Person 的组织必须在允许的列表中。此检查在 iTop 3.0.0 中已添加到用户对象创建/修改和 Person 删除时，但修改 Person 组织到不在允许列表中的组织的情况仍未被保护。&lt;/p>
&lt;p>本教程添加对 Person 类的保护。&lt;/p>
&lt;h2 id="dochecktowrite">DoCheckToWrite&lt;/h2>
&lt;p>必须覆盖此函数：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">DoCheckToWrite&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">array_key_exists&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;org_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ListChanges&lt;/span>&lt;span style="color:#000;font-weight:bold">())&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">HasUserAccount&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">)))&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$iNewOrg&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;org_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$aUserOrgs&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#000">$iNewOrg&lt;/span>&lt;span style="color:#000;font-weight:bold">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sHierarchicalKeyCode&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">IsHierarchicalClass&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;Organization&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sHierarchicalKeyCode&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">!==&lt;/span> &lt;span style="color:#204a87;font-weight:bold">false&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sOrgQuery&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;SELECT Org FROM Organization AS Org JOIN Organization AS Root ON Org.&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#000">$sHierarchicalKeyCode&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#4e9a06">&amp;#39; ABOVE Root.id WHERE Root.id = :id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oOrgFilter&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">DBObjectSearch&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">FromOQL_AllData&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sOrgQuery&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oOrgFilter&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">AllowAllData&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oOrgSet&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">DBObjectSet&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oOrgFilter&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000;font-weight:bold">[],&lt;/span> &lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;id&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$iNewOrg&lt;/span>&lt;span style="color:#000;font-weight:bold">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">while&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$aRow&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oOrgSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">FetchAssoc&lt;/span>&lt;span style="color:#000;font-weight:bold">())&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oOrg&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$aRow&lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;Org&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$aUserOrgs&lt;/span>&lt;span style="color:#000;font-weight:bold">[]&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oOrg&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">GetKey&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oUserSet&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">GetUsers&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">while&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oUser&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oUserSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Fetch&lt;/span>&lt;span style="color:#000;font-weight:bold">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">!&lt;/span>&lt;span style="color:#000">UserRights&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">IsAdministrator&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oUser&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oSet&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oUser&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;allowed_org_list&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Count&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;gt;&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$bFound&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">false&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">while&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oOrg&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oSet&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Fetch&lt;/span>&lt;span style="color:#000;font-weight:bold">())&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">in_array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oOrg&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;allowed_org_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span> &lt;span style="color:#000">$aUserOrgs&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$bFound&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">break&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">!&lt;/span>&lt;span style="color:#000">$bFound&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">m_aCheckErrors&lt;/span>&lt;span style="color:#000;font-weight:bold">[]&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oUser&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;login&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;: &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#000">Dict&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">S&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;Class:User/Error:AllowedOrgsMustContainUserOrg&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#204a87;font-weight:bold">parent&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">DoCheckToWrite&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="辅助函数">辅助函数&lt;/h2>
&lt;p>可选的 Helper 函数：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">GetUsers&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$bActiveOnly&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">false&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$sOQL&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$bActiveOnly&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">?&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;SELECT User WHERE contactid = :person&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ce5c00;font-weight:bold">:&lt;/span> &lt;span style="color:#4e9a06">&amp;#34;SELECT User WHERE contactid = :person AND status=&amp;#39;active&amp;#39;&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oFilter&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">DBSearch&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">FromOQL&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sOQL&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;person&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">GetKey&lt;/span>&lt;span style="color:#000;font-weight:bold">()));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oFilter&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">AllowAllData&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oUserSet&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">new&lt;/span> &lt;span style="color:#000">DBObjectSet&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oFilter&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#000">$oUserSet&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">HasUserAccount&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$bActiveOnly&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">false&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">static&lt;/span> &lt;span style="color:#000">$bHasUserAccount&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">null&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">is_null&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$bHasUserAccount&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$bHasUserAccount&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">GetUsers&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$bActiveOnly&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Count&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;gt;&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#000">$bHasUserAccount&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:user-protection">https://www.itophub.io/wiki/page?id=3_2_0:customization:user-protection&lt;/a>&lt;/p>
&lt;p>2024/09/10 10:25 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/user-protection.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 在 PHP 中添加 TagSet</title><link>/docs/customization/how-to/datamodel/add-value-to-tagset/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-value-to-tagset/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在 PHP 方法中向 TagSet 属性添加特定值。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-value-to-tagset">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>在 PHP 方法中向 TagSet 属性添加特定值。&lt;/p>
&lt;h2 id="前提条件">前提条件&lt;/h2>
&lt;ul>
&lt;li>熟悉&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">教程中使用的语法&lt;/a>&lt;/li>
&lt;li>已&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">创建扩展&lt;/a>&lt;/li>
&lt;li>熟悉仪表盘设计和 OQL&lt;/li>
&lt;/ul>
&lt;h2 id="示例场景">示例场景&lt;/h2>
&lt;p>假设有一个 Bug 类：&lt;/p>
&lt;ul>
&lt;li>字符串字段 &lt;code>version&lt;/code>（继承自 Sprint 的外部字段）&lt;/li>
&lt;li>TagSet &lt;code>versions&lt;/code>（记录修复该 Bug 的产品版本）&lt;/li>
&lt;li>默认情况下，在 Bug 解决时确保至少包含 Sprint 的 &amp;ldquo;version&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;h2 id="代码示例">代码示例&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">PrefillTransitionForm&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&lt;/span>&lt;span style="color:#000">$aContextParam&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">switch&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$aContextParam&lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;stimulus&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">])&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">case&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;ev_resolve&amp;#39;&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">try&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 获取版本字符串
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$sVersion&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;version&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 获取 Bug 应修复的版本（ormTagSet 对象）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$oVersions&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;versions&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 获取对应标签的 TagSetFieldData 代码
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$Tag&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oVersions&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">GetTagFromLabel&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 若不存在则添加
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$oVersions&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Add&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$Tag&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 设置回对象
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;versions&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$oVersions&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span> &lt;span style="color:#204a87;font-weight:bold">catch&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Exception&lt;/span> &lt;span style="color:#000">$e&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 若标签不是有效值，GetTagFromLabel() 会抛出异常
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">IssueLog&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">Warning&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$e&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">break&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="注意事项">注意事项&lt;/h2>
&lt;p>若标签不是 TagSet 中的有效值，将抛出异常：&lt;/p>
&lt;pre tabindex="0">&lt;code>CoreUnexpectedValue: 4.0.0 is not defined as a valid tag for Bug:versions in...
&lt;/code>&lt;/pre>&lt;h2 id="相关主题">相关主题&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-log-entry">在 PHP 中添加日志条目&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-value-to-tagset">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-value-to-tagset&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/add-value-to-tagset.txt · Last modified: 2025/08/04 15:33 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 在 PHP 中添加日志条目</title><link>/docs/customization/how-to/datamodel/add-log-entry/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-log-entry/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在 PHP 方法中向 Caselog 属性添加日志条目。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-log-entry">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>在 PHP 方法中向 Caselog 属性添加特定日志条目。&lt;/p>
&lt;h2 id="前提条件">前提条件&lt;/h2>
&lt;ul>
&lt;li>熟悉&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">教程中使用的语法&lt;/a>&lt;/li>
&lt;li>已&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">创建扩展&lt;/a>&lt;/li>
&lt;li>熟悉仪表盘设计和 OQL&lt;/li>
&lt;/ul>
&lt;h2 id="实现方法">实现方法&lt;/h2>
&lt;ul>
&lt;li>&lt;code>Get()&lt;/code> 在 AttributeCaselog 上返回一个 &lt;code>ormCaselog&lt;/code> 对象&lt;/li>
&lt;li>使用 &lt;code>ormCaselog&lt;/code> 的公共方法 &lt;code>AddLogEntry()&lt;/code>&lt;/li>
&lt;li>将修改后的日志设置回当前对象&lt;/li>
&lt;li>使用 &lt;code>$this-&amp;gt;DBUpdate()&lt;/code> 确保持久化&lt;/li>
&lt;/ul>
&lt;h2 id="代码示例">代码示例&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">PrefillTransitionForm&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&lt;/span>&lt;span style="color:#000">$aContextParam&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">switch&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$aContextParam&lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;stimulus&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">])&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">case&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;ev_resolve&amp;#39;&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 获取日志，返回的是 ormCaselog 对象
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$oLog&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;public_log&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 添加日志条目：文本、创建者标签、可选的用户 ID
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$oLog&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">AddLogEntry&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;The text to add to the log&amp;lt;br&amp;gt;With html tag if needed&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;A text description of the User who added this entry&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ce5c00;font-weight:bold">:&lt;/span>&lt;span style="color:#000">current_user_id&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 将修改后的日志设置回当前对象
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;public_log&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$oLog&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">break&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="相关主题">相关主题&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-value-to-tagset">在 PHP 中添加 TagSet&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-log-entry">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-log-entry&lt;/a>&lt;/p>
&lt;p>2024/09/10 10:25 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/add-log-entry.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 在 Team 上添加仪表盘</title><link>/docs/customization/how-to/datamodel/add-dashboard-attribute/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-dashboard-attribute/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在 Team 对象上添加仪表盘属性，以显示团队相关的信息。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-dashboard-attribute">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>在每个 Team 对象上显示一个仪表盘标签页，包含团队相关的信息，例如：&lt;/p>
&lt;ul>
&lt;li>分配给该团队的开放工单列表&lt;/li>
&lt;li>仅限活跃成员的列表&lt;/li>
&lt;li>至少有一名团队成员所在的位置列表&lt;/li>
&lt;/ul>
&lt;h2 id="参考-oql-查询">参考 OQL 查询&lt;/h2>
&lt;h3 id="开放工单">开放工单&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">SELECT&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">UserRequest&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">WHERE&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">STATUS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">IN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;assigned&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AND&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">team_id&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#000">this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">UNION&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">SELECT&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Incident&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">WHERE&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">STATUS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">IN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;assigned&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AND&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">team_id&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#000">this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">UNION&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">SELECT&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Problem&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">WHERE&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">STATUS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">IN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;assigned&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AND&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">team_id&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#000">this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="活跃成员">活跃成员&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">SELECT&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Person&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">p&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">JOIN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">lnkPersonToTeam&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">l&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ON&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">l&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">person_id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">p&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">WHERE&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">l&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">team_id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#000">this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AND&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">STATUS&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;active&amp;#39;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="成员所在位置">成员所在位置&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">SELECT&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">Location&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">L&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">JOIN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Person&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">P&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ON&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">P&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">location_id&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#000">L&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">JOIN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">lnkPersonToTeam&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">l1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ON&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">l1&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">person_id&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#000">P&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">JOIN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Team&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">T&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ON&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">l1&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">team_id&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#000">T&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">WHERE&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">T&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#000">this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;ol>
&lt;li>进入 Team 类，Schema 标签页创建新字段&lt;/li>
&lt;li>字段代码：&lt;code>overview&lt;/code>&lt;/li>
&lt;li>类型选择：&lt;strong>Dashboard&lt;/strong>&lt;/li>
&lt;li>设置标签&lt;/li>
&lt;/ol>
&lt;p>仪表盘属性可作为对象的额外标签页显示，查询可使用当前对象的上下文。&lt;/p>
&lt;ul>
&lt;li>勾选 &lt;strong>Is User Editable&lt;/strong> 允许普通用户创建自定义版本&lt;/li>
&lt;li>管理员始终可以自定义仪表盘&lt;/li>
&lt;/ul>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="创建仪表盘属性">创建仪表盘属性&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Team&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;dashboard&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeDashboard&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_user_editable&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_user_editable&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;definition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;layout&amp;gt;&lt;/span>DashboardLayoutOneCol&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/layout&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;title/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;auto_reload&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;enabled&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/enabled&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;interval&amp;gt;&lt;/span>300&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/interval&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/auto_reload&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;cells&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;cell&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;0&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dashlets&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dashlet&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;0&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;DashletEmptyCell&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dashlet&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dashlets&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/cell&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/cells&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/definition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;dashboard&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>100&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="设计仪表盘">设计仪表盘&lt;/h3>
&lt;p>先部署一个空仪表盘版本，在 iTop 中直接设计：&lt;/p>
&lt;ol>
&lt;li>使用 &lt;code>:this-&amp;gt;id&lt;/code> 引用当前团队 ID&lt;/li>
&lt;li>设计完成后导出为 XML&lt;/li>
&lt;li>替换初始 &lt;code>&amp;lt;definition&amp;gt;&lt;/code> 的内容&lt;/li>
&lt;/ol>
&lt;p>示例导出：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;?xml version=&amp;#34;1.0&amp;#34;?&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;dashboard&lt;/span> &lt;span style="color:#c4a000">xmlns:xsi=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;layout&amp;gt;&lt;/span>DashboardLayoutOneCol&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/layout&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;title/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;auto_reload&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;enabled&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/enabled&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;interval&amp;gt;&lt;/span>300&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/interval&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/auto_reload&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;cells&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;cell&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;0&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dashlets&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dashlet&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;1&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;DashletObjectList&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;title&amp;gt;&lt;/span>Members&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/title&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;query&amp;gt;&lt;/span>SELECT Person AS p
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> JOIN lnkPersonToTeam AS lnk ON lnk.person_id = p.id
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> WHERE lnk.team_id=:this-&amp;gt;id
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/query&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;menu&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/menu&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dashlet&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dashlets&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/cell&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/cells&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dashboard&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加字典条目">添加字典条目&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;dictionary&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;EN US&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entries&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:Team/Attribute:dashboard&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Overview]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entries&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dictionary&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-dashboard-attribute">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-dashboard-attribute&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/add-dashboard-attribute.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 重新定义字典条目</title><link>/docs/customization/how-to/datamodel/add-dictionay-entry/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-dictionay-entry/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何修改 iTop 中显示的标签以及创建新的字典条目。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-dictionay-entry">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>通过修改字典条目，可以自定义 iTop 中显示的各类标签。了解&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">字典条目命名规范&lt;/a>有助于正确定义条目。&lt;/p>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;h3 id="字典编辑器">字典编辑器&lt;/h3>
&lt;p>在 ITSM Designer 的 &lt;strong>Editors&lt;/strong> 主标签页下，使用 &lt;strong>Dictionary&lt;/strong> 子标签页全局编辑字典条目。&lt;/p>
&lt;h3 id="搜索">搜索&lt;/h3>
&lt;p>使用表单搜索要编辑的字典条目。可以按条目的&lt;strong>代码&lt;/strong>（如 &lt;code>Class:Person&lt;/code>）或&lt;strong>内容&lt;/strong>搜索。若同时提供代码和内容条件，则只显示同时匹配两者的条目。&lt;/p>
&lt;h3 id="修改条目">修改条目&lt;/h3>
&lt;p>修改后，点击每个条目旁的验证标记，或使用顶部的 &lt;strong>Apply All&lt;/strong> 按钮应用所有更改。&lt;/p>
&lt;h3 id="缺失翻译">缺失翻译&lt;/h3>
&lt;p>可以搜索尚未翻译的条目。&lt;/p>
&lt;h3 id="新建条目">新建条目&lt;/h3>
&lt;p>若字典条目不存在（例如来自 XML 门户的新条目），可使用 &lt;strong>New&lt;/strong> 按钮创建。&lt;/p>
&lt;h3 id="删除条目">删除条目&lt;/h3>
&lt;p>搜索条目，选择要删除的条目，然后点击删除按钮。&lt;/p>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="修改-xml-条目">修改 XML 条目&lt;/h3>
&lt;p>首先找到条目的&lt;strong>代码&lt;/strong>。通用标签位于 &lt;code>your-itop/dictionary/en.dictionary.itop.xxx.php&lt;/code> 文件中：&lt;/p>
&lt;ul>
&lt;li>&lt;code>ui&lt;/code> — 用户界面标签&lt;/li>
&lt;li>&lt;code>core&lt;/code> — 字段类型和通用对象标签&lt;/li>
&lt;/ul>
&lt;p>数据模型类相关的标签位于 &lt;code>your-itop/datamodels/2.x/xxx/en.dict.xxx.php&lt;/code> 中。&lt;/p>
&lt;p>找到代码后，在扩展中重新定义其值。使用 &lt;code>_delta=&amp;quot;redefine&amp;quot;&lt;/code> 替换现有值，使用 &lt;code>_delta=&amp;quot;force&amp;quot;&lt;/code> 在不确定是否存在时强制设置。&lt;/p>
&lt;p>示例：将 UserRequest 的 &amp;ldquo;Requestor&amp;rdquo; 改为 &amp;ldquo;Beneficiary&amp;rdquo;：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;dictionary&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;EN US&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entries&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:UserRequest/Attribute:caller_id&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redefine&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Beneficiary]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:UserRequest/Attribute:caller_id+&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;force&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Choose the client person who will get the requested service]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entries&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dictionary&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="新建-xml-条目">新建 XML 条目&lt;/h3>
&lt;p>使用 &lt;code>_delta=&amp;quot;define&amp;quot;&lt;/code> 创建新条目，若条目已存在则会失败。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;dictionary&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;EN US&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entries&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:Team/Attribute:dashboard&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[Overview]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entries&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dictionary&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如需为多语言定义标签，可复制上述 XML 结构并修改语言代码。&lt;/p>
&lt;h3 id="使用字典文件">使用字典文件&lt;/h3>
&lt;p>除在 XML 中定义外，也可在 PHP 文件中按语言定义字典条目。详见&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">iTop 翻译&lt;/a>。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-dictionay-entry">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-dictionay-entry&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/add-dictionay-entry.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 转换方法</title><link>/docs/customization/how-to/datamodel/actions-on-transitions/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/actions-on-transitions/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍在 iTop 生命周期转换中可用的预定义 PHP 方法及其参数。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:actions-on-transitions">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>在 XML 生命周期定制中，当对象发生特定转换时，可能需要执行某些动作。这些动作是对象类的 PHP 方法。您既可以编写自定义方法，也可以使用 DBObject 上已声明的现有方法。&lt;/p>
&lt;h2 id="前提条件">前提条件&lt;/h2>
&lt;ul>
&lt;li>熟悉&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">教程中使用的语法&lt;/a>&lt;/li>
&lt;li>已&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">创建扩展&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="参数说明">参数说明&lt;/h2>
&lt;h3 id="sattcode">$sAttCode&lt;/h3>
&lt;ul>
&lt;li>字符串类型，必须是当前类的有效属性代码&lt;/li>
&lt;li>不提供有效性检查，若代码无效将导致致命错误&lt;/li>
&lt;li>可在 XML 类定义的 &lt;code>field id&lt;/code> 中找到&lt;/li>
&lt;li>也可在 iTop 的数据模型查看器中找到，使用属性的&lt;strong>代码&lt;/strong>而非标签&lt;/li>
&lt;/ul>
&lt;h3 id="value">$value&lt;/h3>
&lt;ul>
&lt;li>固定字面量值，通常为字符串，也可以是数字&lt;/li>
&lt;/ul>
&lt;h2 id="可用方法">可用方法&lt;/h2>
&lt;h3 id="addvaluesattcode-ivalue--1">AddValue($sAttCode, $iValue = 1)&lt;/h3>
&lt;p>递增或递减当前对象的字段值。&lt;/p>
&lt;ul>
&lt;li>不对字段类型或值进行控制，无效组合将导致 iTop 崩溃&lt;/li>
&lt;li>&lt;code>$value&lt;/code> 应为数字或浮点数，可为负数&lt;/li>
&lt;li>&lt;code>$sAttCode&lt;/code> 应为 Decimal、Integer、Percentage 或 Duration 类型的属性代码&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;1&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;verb&amp;gt;&lt;/span>AddValue&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/verb&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;params&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;param&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;1&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;string&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>assign_counter&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/param&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;param&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;2&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;integer&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>1&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/param&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/params&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="copysdestattcode-ssourceattcode">Copy($sDestAttCode, $sSourceAttCode)&lt;/h3>
&lt;p>将当前对象的一个字段内容复制到另一个字段。&lt;/p>
&lt;ul>
&lt;li>不检查属性代码的有效性和一致性&lt;/li>
&lt;li>如需要会将 HTML 转换为文本&lt;/li>
&lt;li>日期和数字自动转换为文本&lt;/li>
&lt;/ul>
&lt;h3 id="resetsattcode">Reset($sAttCode)&lt;/h3>
&lt;p>将指定字段重置为默认值。&lt;/p>
&lt;h3 id="resetstopwatchsattcode">ResetStopWatch($sAttCode)&lt;/h3>
&lt;p>重置秒表属性。&lt;/p>
&lt;ul>
&lt;li>会验证是否为当前对象的秒表属性&lt;/li>
&lt;li>清空 TimeSpent&lt;/li>
&lt;li>重置后如同从未停止过&lt;/li>
&lt;li>若正在运行，则从头开始计时&lt;/li>
&lt;/ul>
&lt;h3 id="setsattcode-value">Set($sAttCode, $value)&lt;/h3>
&lt;p>为指定属性设置固定值。不检查代码格式或值的有效性。&lt;/p>
&lt;ul>
&lt;li>例如设置 Ticket 的 &lt;code>caller_id&lt;/code> 时，&lt;code>$value&lt;/code> 必须是 iTop 中存在的 Person 对象的数字 ID&lt;/li>
&lt;li>枚举类型的 &lt;code>$value&lt;/code> 应使用代码而非标签&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;caller_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">6&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="setifnullsattcode-value">SetIfNull($sAttCode, $value)&lt;/h3>
&lt;p>与 &lt;code>Set&lt;/code> 相同，但如果字段已有值则保持不变。&lt;/p>
&lt;h3 id="setcomputeddatesattcode-smodifier---sattcodesource--">SetComputedDate($sAttCode, $sModifier = &amp;lsquo;&amp;rsquo;, $sAttCodeSource = &amp;lsquo;&amp;rsquo;)&lt;/h3>
&lt;p>从源日期（省略则使用当前时间）计算新日期，应用修饰符后复制到目标字段。&lt;/p>
&lt;p>修饰符示例：&lt;/p>
&lt;ul>
&lt;li>&lt;code>+5 days&lt;/code> — 5 天后&lt;/li>
&lt;li>&lt;code>-3 weeks&lt;/code> — 3 周前&lt;/li>
&lt;li>&lt;code>first weekday of next month&lt;/code> — 下月第一个工作日&lt;/li>
&lt;li>&lt;code>monday of next week&lt;/code> — 下周一&lt;/li>
&lt;/ul>
&lt;h3 id="setcomputeddateifnullsattcode-smodifier---sattcodesource--">SetComputedDateIfNull($sAttCode, $sModifier = &amp;lsquo;&amp;rsquo;, $sAttCodeSource = &amp;lsquo;&amp;rsquo;)&lt;/h3>
&lt;p>与 &lt;code>SetComputedDate&lt;/code> 相同，但如果字段已有值则保持不变。&lt;/p>
&lt;h3 id="setcurrentpersonsattcode">SetCurrentPerson($sAttCode)&lt;/h3>
&lt;p>将当前执行方法的用户的关联 Person 设置到指定字段。&lt;/p>
&lt;ul>
&lt;li>若字段是指向 Person 类或其父类的外部键：复制关联 Person 的 ID&lt;/li>
&lt;li>若字段是指向其他类的外部键：将导致崩溃&lt;/li>
&lt;li>若字段是字符串：放入关联 Person 的友好名称&lt;/li>
&lt;/ul>
&lt;h3 id="setcurrentdatesattcode">SetCurrentDate($sAttCode)&lt;/h3>
&lt;p>将 Date 或 DateTime 属性设置为当前时间。&lt;/p>
&lt;h3 id="setcurrentdateifnullsattcode">SetCurrentDateIfNull($sAttCode)&lt;/h3>
&lt;p>与 &lt;code>SetCurrentDate&lt;/code> 相同，但如果字段已有值则保持不变。&lt;/p>
&lt;h3 id="setelapsedtimesattcode-srefattcode-sworkingtimecomputer--null">SetElapsedTime($sAttCode, $sRefAttCode, $sWorkingTimeComputer = null)&lt;/h3>
&lt;p>检查 &lt;code>itop/core/dbobject.class.inc.php&lt;/code> 中的代码了解详情。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:actions-on-transitions">https://www.itophub.io/wiki/page?id=3_2_0:customization:actions-on-transitions&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/actions-on-transitions.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 转换时执行动作</title><link>/docs/customization/how-to/datamodel/add-counter/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-counter/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在工单状态转换时执行动作，以统计工单重新打开次数为例。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-counter">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>本用例演示如何统计用户请求被重新打开的次数。需要：&lt;/p>
&lt;ul>
&lt;li>为用户请求添加计数器字段&lt;/li>
&lt;li>可选：禁用历史追踪&lt;/li>
&lt;li>修改生命周期，在从 &lt;code>resolved&lt;/code> 到 &lt;code>assigned&lt;/code> 的转换时调用方法&lt;/li>
&lt;li>修改展示以显示计数器&lt;/li>
&lt;li>为计数器字段添加标签&lt;/li>
&lt;/ul>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;h3 id="添加字段">添加字段&lt;/h3>
&lt;ol>
&lt;li>进入 UserRequest 类，在 Schema 标签页创建新字段&lt;/li>
&lt;li>字段代码：&lt;code>reopen_counter&lt;/code>（仅小写字母，无空格或特殊字符）&lt;/li>
&lt;li>类型选择：&lt;strong>Number (Integer)&lt;/strong>&lt;/li>
&lt;li>定义标签&lt;/li>
&lt;li>可选：禁用历史追踪&lt;/li>
&lt;/ol>
&lt;h3 id="修改生命周期">修改生命周期&lt;/h3>
&lt;ol>
&lt;li>进入 Lifecycle 标签页&lt;/li>
&lt;li>在图中选择从 &lt;code>resolved&lt;/code> 到 &lt;code>assigned&lt;/code> 的转换&lt;/li>
&lt;li>在右侧面板点击动作列表底部的按钮&lt;/li>
&lt;li>在对话框中选择方法 &lt;code>AddValue&lt;/code>&lt;/li>
&lt;li>目标字段选择 &lt;code>reopen_counter&lt;/code>&lt;/li>
&lt;li>值输入 &lt;code>1&lt;/code>&lt;/li>
&lt;/ol>
&lt;h3 id="修改展示">修改展示&lt;/h3>
&lt;p>进入 Presentation 标签页，将 &lt;code>reopen_counter&lt;/code> 添加到 UserRequest 的详情视图中。&lt;/p>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="添加计数器字段">添加计数器字段&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;classes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;UserRequest&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;reopen_count&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeInteger&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;sql&amp;gt;&lt;/span>reopen_count&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/sql&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;default_value&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/default_value&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/classes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="禁用历史追踪可选">禁用历史追踪（可选）&lt;/h3>
&lt;p>若不需要记录计数器每次变更的历史：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;reopen_count&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;tracking_level&amp;gt;&lt;/span>none&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/tracking_level&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="在转换时调用方法">在转换时调用方法&lt;/h3>
&lt;p>在从 &lt;code>resolved&lt;/code> 到 &lt;code>assigned&lt;/code> 的转换时递增计数器：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;resolved&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transition&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_reopen&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;actions&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redefine&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;verb&amp;gt;&lt;/span>AddValue&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/verb&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;params&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;param&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;attcode&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>reopen_count&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/param&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;param&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;int&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>1&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/param&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/params&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/action&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/actions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="声明自定义-php-方法">声明自定义 PHP 方法&lt;/h3>
&lt;p>若预定义方法不满足需求，可创建自定义方法：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">MyLifecycleMethod&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sAttCode&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$iIncrement&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">IsValidAttCode&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">get_class&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span> &lt;span style="color:#000">$sAttCode&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#000">is_numeric&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$iIncrement&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">GetAttributeDef&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">get_class&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span> &lt;span style="color:#000">$sAttCode&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000">instanceof&lt;/span> &lt;span style="color:#000">AttributeInteger&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$iNew&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sAttCode&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">+&lt;/span> &lt;span style="color:#000">$iIncrement&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$sAttCode&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$iNew&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加展示">添加展示&lt;/h3>
&lt;p>将计数器添加到 UserRequest 详情页的 SLA 报告字段集中：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;UserRequest&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;col:col3&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;fieldset:Ticket:SLA&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;item&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;reopen_count&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>80&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/item&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/items&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/details&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/presentation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加标签">添加标签&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:UserRequest/Attribute:reopen_count&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>重新打开计数器&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-counter">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-counter&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/add-counter.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 转换时字段必填</title><link>/docs/customization/how-to/datamodel/mandatory-on-transition/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/mandatory-on-transition/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在生命周期转换时或特定状态中强制字段必填。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-on-transition">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>当对象具有生命周期时，iTop 数据模型允许在转换和状态级别指定哪些字段必须填写。&lt;/p>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;h3 id="转换时必填">转换时必填&lt;/h3>
&lt;p>要求从 New 状态移动到 Assigned 状态时填写 Service 字段：&lt;/p>
&lt;ol>
&lt;li>在 Lifecycle 标签页中选择转换&lt;/li>
&lt;li>设置字段为必填&lt;/li>
&lt;/ol>
&lt;h3 id="状态中必填">状态中必填&lt;/h3>
&lt;p>要求所有处于 Assigned 状态的 UserRequest 都定义 Service：&lt;/p>
&lt;ol>
&lt;li>在 Lifecycle 标签页中选择状态&lt;/li>
&lt;li>设置字段为必填&lt;/li>
&lt;/ol>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="转换时必填-1">转换时必填&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;UserRequest&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;lifecycle&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;new&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;transition&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ev_assign&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;service_id&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;mandatory/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/flags&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transition&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/transitions&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/lifecycle&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="状态中必填-1">状态中必填&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;UserRequest&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;lifecycle&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;assigned&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;flags&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;service_id&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;mandatory/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/attribute&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/flags&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/lifecycle&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="迁移注意事项">迁移注意事项&lt;/h2>
&lt;p>Setup 时无可见效果，但不符合要求的对象将无法在控制台或门户中修改，直到提供 Service。建议创建审计规则检索不符合要求的对象并修复。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-on-transition">https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-on-transition&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/mandatory-on-transition.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 状态延迟后通知</title><link>/docs/customization/how-to/datamodel/add-stopwatch/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/add-stopwatch/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在工单在特定状态中停留超过指定时间后发送通知。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-stopwatch">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>当工单在 &lt;code>assigned&lt;/code> 状态中超过 2 小时和 6 小时时分别通知相关人员。需要：&lt;/p>
&lt;ul>
&lt;li>定义实现 &lt;code>iMetricComputer&lt;/code> 的 PHP 类，计算固定延迟作为秒表目标&lt;/li>
&lt;li>在 UserRequest 上添加秒表属性，在 &lt;code>assigned&lt;/code> 状态时计时，使用固定目标&lt;/li>
&lt;li>设置工作时间计算方式&lt;/li>
&lt;/ul>
&lt;h2 id="使用-itsm-designercombodo-客户">使用 ITSM Designer（Combodo 客户）&lt;/h2>
&lt;h3 id="定义目标">定义目标&lt;/h3>
&lt;p>需要 &amp;ldquo;Designer PHP developer&amp;rdquo; 配置文件。定义 6 小时延迟，在 2 小时（33%）和 6 小时（100%）时通知：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">class&lt;/span> &lt;span style="color:#000">FixedDelayMetric&lt;/span> &lt;span style="color:#204a87;font-weight:bold">implements&lt;/span> &lt;span style="color:#000">iMetricComputer&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">static&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">GetDescription&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#4e9a06">&amp;#34;iTop configurable delay in hours, 6 by default&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">ComputeMetric&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oObject&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$iRes&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">3600&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">*&lt;/span> &lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">GetConfig&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">GetModuleSetting&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;itop-tickets&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;pending_delay&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;6&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#000">$iRes&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在 iTop 配置文件中添加：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">$MyModuleSettings&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;itop-tickets&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#204a87;font-weight:bold">array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#4e9a06">&amp;#39;pending_delay&amp;#39;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&amp;gt;&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">36&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加秒表">添加秒表&lt;/h3>
&lt;ol>
&lt;li>创建秒表，选择状态 &lt;code>assigned&lt;/code>&lt;/li>
&lt;li>在 33% 处添加阈值&lt;/li>
&lt;li>在 100% 处添加阈值&lt;/li>
&lt;/ol>
&lt;h3 id="定义工作时间">定义工作时间&lt;/h3>
&lt;ul>
&lt;li>使用 &lt;code>DefaultWorkingTimeComputer&lt;/code> 进行 24x7 计时&lt;/li>
&lt;li>使用 &lt;code>SLAComputation&lt;/code> 考虑工作时段（通常仅适用于子工单类）&lt;/li>
&lt;/ul>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;h3 id="定义目标-1">定义目标&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">class&lt;/span> &lt;span style="color:#000">FixedDelayMetric&lt;/span> &lt;span style="color:#204a87;font-weight:bold">implements&lt;/span> &lt;span style="color:#000">iMetricComputer&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">static&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">GetDescription&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#4e9a06">&amp;#34;Fixed 6h delay&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">ComputeMetric&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oObject&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$iRes&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">6&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">*&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">3600&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span> &lt;span style="color:#8f5902;font-style:italic">// 目标以秒为单位
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#204a87;font-weight:bold">return&lt;/span> &lt;span style="color:#000">$iRes&lt;/span>&lt;span style="color:#000;font-weight:bold">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="添加秒表-1">添加秒表&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;fixdelay&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeStopWatch&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;assigned&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>assigned&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;working_time&amp;gt;&lt;/span>DefaultWorkingTimeComputer&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/working_time&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;thresholds/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;goal&amp;gt;&lt;/span>FixedDelayMetric&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/goal&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;always_load_in_tables&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/always_load_in_tables&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Class:UserRequest/Attribute:fixdelay&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[6h Delay]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="配置通知">配置通知&lt;/h2>
&lt;p>在 iTop 中定义基于阈值的触发器，并链接到通知动作。使用新创建的秒表 &lt;code>fixdelay&lt;/code>，可用阈值为 33 和 100。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-stopwatch">https://www.itophub.io/wiki/page?id=3_2_0:customization:add-stopwatch&lt;/a>&lt;/p>
&lt;p>2024/09/10 10:25 by127.0.0.1&lt;/p>
&lt;p>版本：3_2_0/customization/add-stopwatch.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 追踪对象创建者</title><link>/docs/customization/how-to/datamodel/tracking-creator/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/tracking-creator/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何追踪对象的创建者。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:tracking-creator">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="概述">概述&lt;/h2>
&lt;p>对象历史记录中包含创建者信息，但难以通过 OQL 查询，也无法构建按创建者统计的仪表盘。解决方案：&lt;/p>
&lt;ul>
&lt;li>在 Ticket 或 UserRequest 上添加 &lt;code>creator_id&lt;/code> 字段（指向 Person 类的外部键）&lt;/li>
&lt;li>自动存储对象创建者&lt;/li>
&lt;li>通过查询历史记录更新现有工单&lt;/li>
&lt;/ul>
&lt;h2 id="添加-creator_id-字段">添加 creator_id 字段&lt;/h2>
&lt;p>参考&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-attribute-sample">为 Server 类添加字段&lt;/a>。&lt;/p>
&lt;p>若决定在 UserRequest、Incident、Change 等详情中显示 &lt;code>creator_id&lt;/code>，建议将其设为&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:start">只读&lt;/a>。&lt;/p>
&lt;h2 id="自动填充创建者">自动填充创建者&lt;/h2>
&lt;p>Ticket 创建时自动使用当前用户的关联人员初始化 &lt;code>creator_id&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">protected&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">OnInsert&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;creator_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">UserRights&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">GetContactId&lt;/span>&lt;span style="color:#000;font-weight:bold">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">parent&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">OnInsert&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>然后运行 Setup 使新字段生效。&lt;/p>
&lt;h2 id="数据初始化">数据初始化&lt;/h2>
&lt;h3 id="1-运行查询">1. 运行查询&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">SELECT&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">co&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">p&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">FROM&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">CMDBChangeOp&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">co&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">JOIN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">CMDBChange&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">c&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ON&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">co&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">change&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#204a87;font-weight:bold">c&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">JOIN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Ticket&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">t&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ON&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">co&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">objkey&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#000">t&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">JOIN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">USER&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">u&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ON&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">c&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">user_id&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#000">u&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">JOIN&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Person&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">AS&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">p&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ON&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">u&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">contactid&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#000">p&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">id&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">WHERE&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">co&lt;/span>&lt;span style="color:#000;font-weight:bold">.&lt;/span>&lt;span style="color:#000">finalclass&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;CMDBChangeOpCreate&amp;#34;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-csv-导入">2. CSV 导入&lt;/h3>
&lt;p>使用高级模式导入两列：&lt;/p>
&lt;ul>
&lt;li>&lt;code>co.object_id&lt;/code> -&amp;gt; Ticket id（主键）&lt;/li>
&lt;li>&lt;code>p.id&lt;/code>（主键）-&amp;gt; Creator&lt;/li>
&lt;/ul>
&lt;p>导入到 UserRequest 和 Incident。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:tracking-creator">https://www.itophub.io/wiki/page?id=3_2_0:customization:tracking-creator&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/tracking-creator.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 额外的创建状态</title><link>/docs/customization/how-to/datamodel/create-in-different-states/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/create-in-different-states/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在 iTop 中允许对象在除默认状态外的其他生命周期状态中创建。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:create-in-different-states">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="目标">目标&lt;/h2>
&lt;p>假设我们有一个带有生命周期的 &lt;code>Task&lt;/code> 类，默认情况下 &lt;code>Task&lt;/code> 在 &lt;code>new&lt;/code> 状态中创建。我们希望也允许在另一个状态 &lt;code>template&lt;/code> 中创建 Task。&lt;/p>
&lt;h2 id="使用-designer">使用 Designer&lt;/h2>
&lt;p>&lt;strong>前提条件：&lt;/strong> 必须是 Combodo 客户。&lt;/p>
&lt;p>此操作只能由 Combodo 执行。&lt;/p>
&lt;h2 id="使用-itop-扩展">使用 iTop 扩展&lt;/h2>
&lt;p>&lt;strong>前提条件：&lt;/strong> 请先查看 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:add-state">添加状态和转换&lt;/a> 教程。&lt;/p>
&lt;p>在 &lt;code>template&lt;/code> 状态声明中，只需添加 3 行即可：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;states&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;template&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;initial_state_path&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;state_ref&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>new&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/state_ref&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/initial_state_path&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:create-in-different-states">https://www.itophub.io/wiki/page?id=3_2_0:customization:create-in-different-states&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/create-in-different-states.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: LinkedSet 相关值</title><link>/docs/customization/how-to/datamodel/event-db-links-changed/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/event-db-links-changed/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在 iTop 3.1+ 中处理 LinkedSet 相关值的计算与约束。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:event-db-links-changed">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="场景">场景&lt;/h2>
&lt;p>假设我们有一个 &lt;code>Stock&lt;/code> 对象类，以及一个通过 1:n 关系与之关联的 &lt;code>StockMove&lt;/code> 类：&lt;/p>
&lt;ul>
&lt;li>&lt;code>Stock&lt;/code> 对象有可用商品数量&lt;/li>
&lt;li>当有人要消耗库存中的某些商品时，创建一个带有所需数量的 &lt;code>StockMove&lt;/code> 对象&lt;/li>
&lt;li>如果所需数量超过库存中的可用商品，iTop 必须拒绝此消耗&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>在 iTop 3.1 之前：&lt;/strong> 可以在 &lt;code>Stock&lt;/code> 类的 &lt;code>OnUpdate&lt;/code> / &lt;code>OnInsert&lt;/code> 中计算，但这假设没有其他方式可以在不编辑 &lt;code>Stock&lt;/code> 对象的情况下创建/修改/删除 LinkedSet 中的对象。&lt;/p>
&lt;p>&lt;strong>自 iTop 3.1 起：&lt;/strong> 可以仅编辑关系，而宿主 &lt;code>Stock&lt;/code> 对象处于只读模式，因此 &lt;code>OnUpdate&lt;/code> / &lt;code>OnInsert&lt;/code> 不会触发，计算值也不会更新。可以使用 &lt;code>AttributeLinkedSet(Indirect)&lt;/code> XML 标签 &lt;code>&amp;lt;edit_when&amp;gt;in_host_edition&amp;lt;/edit_when&amp;gt;&lt;/code> 阻止在 &lt;code>Stock&lt;/code> 对象只读时编辑 LinkedSet，但这不够用户友好。&lt;/p>
&lt;p>下面介绍另一种替代方案。&lt;/p>
&lt;h2 id="计算-linkedset-依赖值">计算 LinkedSet 依赖值&lt;/h2>
&lt;p>我们需要计算依赖于 &lt;code>stockmoves_list&lt;/code> 这个 LinkedSet 属性的内容，并将其存储在 &lt;code>Stock&lt;/code> 类上。&lt;/p>
&lt;ul>
&lt;li>计算方法为 &lt;code>ComputeAndUpdateStock()&lt;/code>，它计算并更新 &lt;code>Stock&lt;/code> 字段 &lt;code>remaining_quantity&lt;/code>&lt;/li>
&lt;li>&lt;code>StockMove&lt;/code> 对象有一个指向 &lt;code>MyClass&lt;/code> 的必填外部键，以及 &lt;code>quantity&lt;/code> 和 &lt;code>type&lt;/code>（表示是消耗还是补充库存）&lt;/li>
&lt;li>我们希望无论 LinkedSet 内容以何种方式修改，该值始终保持最新&lt;/li>
&lt;li>&lt;code>StockMove&lt;/code> 的创建、修改或删除都需要重新计算 &lt;code>Stock&lt;/code> 的 &lt;code>remaining_quantity&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>实现步骤：&lt;/p>
&lt;ol>
&lt;li>在 LinkedSet 属性上标记 &lt;code>&amp;lt;with_php_computation&amp;gt;true&amp;lt;/with_php_computation&amp;gt;&lt;/code>&lt;/li>
&lt;li>监听 &lt;code>EVENT_DB_LINKS_CHANGED&lt;/code> 事件并执行计算&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;stockmoves_list&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeLinkedSet&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;ext_key_to_me&amp;gt;&lt;/span>stock_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/ext_key_to_me&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;linked_class&amp;gt;&lt;/span>StockMove&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/linked_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;tracking_level&amp;gt;&lt;/span>none&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/tracking_level&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;count_min/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;count_max/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;with_php_constraint&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/with_php_constraint&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;with_php_computation&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/with_php_computation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;edit_mode&amp;gt;&lt;/span>none&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/edit_mode&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;OnLinksChanged&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_LINKS_CHANGED&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>OnLinksChanged&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;methods&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">OnLinksChanged&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ComputeAndUpdateStock&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// $this-&amp;gt;DBUpdate(); 在 $this 上不需要
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#8f5902;font-style:italic">// 如果 ComputeAndUpdateStock() 修改了 $this，iTop 将自动执行 DBUpdate()
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">protected&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">OnUpdate&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$aChanges&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ListChanges&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">/* 不要在此计算，因为 EVENT_DB_LINKS_CHANGED 会被调用一次并执行计算
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> if (array_key_exists(&amp;#39;stockmoves_list&amp;#39;, $aChanges)) {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> $this-&amp;gt;ComputeAndUpdateStock();
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"> } */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="阻止-linkedset-的无效变更">阻止 LinkedSet 的无效变更&lt;/h2>
&lt;p>&lt;strong>目标：&lt;/strong> 阻止导致库存为负值的 &lt;code>StockMove&lt;/code> 创建/修改/删除。&lt;/p>
&lt;p>当条件只能由宿主对象检查时，阻止对 &lt;code>stockmoves_list&lt;/code> 的操作：&lt;/p>
&lt;ul>
&lt;li>方法 &lt;code>ComputeStock()&lt;/code> 计算库存的理论 &amp;ldquo;剩余数量&amp;rdquo;，但不更新 &lt;code>remaining_quantity&lt;/code> 字段，仅用于检查&lt;/li>
&lt;li>同样，&lt;code>StockMove&lt;/code> 对象有指向 &lt;code>MyClass&lt;/code> 的必填外部键、数量 &lt;code>quantity&lt;/code> 和类型 &lt;code>type&lt;/code>&lt;/li>
&lt;li>我们希望阻止导致库存出现负值的 &lt;code>StockMove&lt;/code> 创建/修改/删除&lt;/li>
&lt;/ul>
&lt;p>实现步骤：&lt;/p>
&lt;ol>
&lt;li>在 LinkedSet 上标记 &lt;code>&amp;lt;with_php_constraint&amp;gt;true&amp;lt;/with_php_constraint&amp;gt;&lt;/code>&lt;/li>
&lt;li>监听 &lt;code>EVENT_DB_CHECK_TO_WRITE&lt;/code> 事件，在 LinkedSet 上检查条件，如需阻止则添加 Check Issue&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;stockmoves_list&amp;#34;&lt;/span> &lt;span style="color:#c4a000">xsi:type=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AttributeLinkedSet&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;ext_key_to_me&amp;gt;&lt;/span>stock_id&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/ext_key_to_me&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;linked_class&amp;gt;&lt;/span>StockMove&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/linked_class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;tracking_level&amp;gt;&lt;/span>none&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/tracking_level&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;count_min/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;count_max/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;with_php_constraint&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/with_php_constraint&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;with_php_computation&amp;gt;&lt;/span>true&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/with_php_computation&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;edit_mode&amp;gt;&lt;/span>none&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/edit_mode&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;CheckStockAvailability&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_CHECK_TO_WRITE&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>CheckStockAvailability&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">CheckStockAvailability&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 如果所需数量在库存中不可用则停止
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#8f5902;font-style:italic">// ComputeStock() 不修改 $this，仅计算
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ComputeStock&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;lt;&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 添加 CheckIssue 将阻止链接对象的创建/修改或删除
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">AddCheckIssue&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Dict&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">Format&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;Stock:Error:NotEnoughQuantityInStock&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="其他用例">其他用例&lt;/h2>
&lt;ul>
&lt;li>在机柜（Enclosure）中可以定义其总容量（U 大小）&lt;/li>
&lt;li>机柜包含的设备也有 U 大小&lt;/li>
&lt;li>一个设备只能位于单个机柜中&lt;/li>
&lt;li>机柜上的 &lt;code>devices_list&lt;/code> 是 LinkedSet 属性&lt;/li>
&lt;li>可以使用上述方法阻止已安装设备的 U 大小总和超过机柜的 U 大小&lt;/li>
&lt;/ul>
&lt;h2 id="局限性">局限性&lt;/h2>
&lt;p>假设在一个团队中，我们希望确保团队成员中男性和女性的数量 &amp;ldquo;相同，正负不超过两人&amp;rdquo;。&lt;/p>
&lt;ul>
&lt;li>每次添加或删除成员时，规则会自动检查，当变更会破坏规则时阻止添加或删除&lt;/li>
&lt;li>但可以通过更改某个团队成员的性别来绕过规则，因为此更改不会触发团队检查&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>如果删除一个人员，删除传播是否正确执行？如果团队引发了 CheckToWrite 问题，这是否会被阻止？&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:event-db-links-changed">https://www.itophub.io/wiki/page?id=3_2_0:customization:event-db-links-changed&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/event-db-links-changed.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 隐藏转换</title><link>/docs/customization/how-to/datamodel/hide-transition/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/hide-transition/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何限制工单的转换操作，仅允许处理人、其经理或管理员执行。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:hide-transition">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="目标">目标&lt;/h2>
&lt;p>在本教程中，我们将了解如何阻止除处理人、其经理或管理员之外的其他人转换工单。&lt;/p>
&lt;p>我们将使用 &lt;code>EVENT_ENUM_TRANSITIONS&lt;/code> 事件的回调。&lt;/p>
&lt;h2 id="实现逻辑">实现逻辑&lt;/h2>
&lt;ol>
&lt;li>获取处理人（agent）的 Person 对象&lt;/li>
&lt;li>检查是否处于应隐藏转换的情况：
&lt;ul>
&lt;li>当前连接用户的 ID（&lt;code>UserRights::GetContactId()&lt;/code>）既不是 &lt;code>agent_id&lt;/code> 也不是其 &lt;code>manager_id&lt;/code>&lt;/li>
&lt;li>当前用户不是 iTop 管理员（&lt;code>!UserRights::IsAdministrator()&lt;/code>）&lt;/li>
&lt;li>工单处于 &amp;ldquo;Assigned&amp;rdquo; 或 &amp;ldquo;Pending&amp;rdquo; 状态&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>然后使用 &lt;code>$this-&amp;gt;DenyTransition($sStimulusCode)&lt;/code> 移除应受限的激励（stimulus）
&lt;ul>
&lt;li>可以隐藏不存在的激励，不会产生任何影响&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;h2 id="xml-配置">XML 配置&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;classes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;UserRequest&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;HideTransitionsIfNotAgent&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_ENUM_TRANSITIONS&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>HideTransitionsIfNotAgent&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;methods&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;method&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;HideTransitionsIfNotAgent&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;comment&amp;gt;&lt;/span>/**
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> * 如果当前用户既不是处理人，也不是其经理
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> * 且当前用户不是管理员
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> * 且 UserRequest 处于某些状态
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> * 则隐藏某些转换
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> */&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/comment&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;static&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/static&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;access&amp;gt;&lt;/span>public &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/access&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;code&amp;gt;&lt;/span>&lt;span style="color:#a40000">&amp;lt;&lt;/span>![CDATA[public function HideTransitionsIfNotAgent(Combodo\iTop\Service\Events\EventData $oEventData)....
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="php-代码">PHP 代码&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">HideTransitionsIfNotAgent&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$iAgent&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;agent_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$iAgent&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;gt;&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oAgent&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">GetObject&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;Person&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$iAgent&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$iManager&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oAgent&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;manager_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$iCurrentPerson&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">UserRights&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">GetContactId&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">((&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">!&lt;/span>&lt;span style="color:#000">in_array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$iCurrentPerson&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#000">$iAgent&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$iManager&lt;/span>&lt;span style="color:#000;font-weight:bold">])&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">!&lt;/span>&lt;span style="color:#000">UserRights&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">IsAdministrator&lt;/span>&lt;span style="color:#000;font-weight:bold">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">in_array&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;status&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span> &lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;assigned&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;pending&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">])))&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DenyTransition&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;ev_pending&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DenyTransition&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;ev_resolve&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:hide-transition">https://www.itophub.io/wiki/page?id=3_2_0:customization:hide-transition&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/hide-transition.txt · Last modified: 2025/11/18 18:05 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 添加附件时记录日志</title><link>/docs/customization/how-to/datamodel/log-attachment/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/log-attachment/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在添加或删除附件时自动向工单日志添加记录。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:log-attachment">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="目标">目标&lt;/h2>
&lt;p>需求：每次有人向工单添加附件时，在 UserRequest 工单的日志中添加一条记录。&lt;/p>
&lt;p>利用事件机制，可以订阅特定事件并在事件触发时执行方法。&lt;/p>
&lt;ul>
&lt;li>在 UserRequest 类上创建一个方法来添加日志条目&lt;/li>
&lt;li>订阅两个不同的事件并指定回调方法&lt;/li>
&lt;/ul>
&lt;h2 id="添加日志条目">添加日志条目&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">AddLogEntryOnAttachment&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 获取日志，返回的对象是 ormCaselog，即一个对象
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$oLog&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;public_log&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 从事件中获取 Attachment 对象
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$oAttachment&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;attachment&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 从 Attachment 获取 ormDocument
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$oDocument&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#000">$oAttachment&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;contents&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 测试哪个&amp;#34;事件&amp;#34;触发了回调
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">GetEvent&lt;/span>&lt;span style="color:#000;font-weight:bold">()&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#000">EVENT_ADD_ATTACHMENT_TO_OBJECT&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 添加一条日志条目，包含附件文件名
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$oLog&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">AddLogEntry&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;Add an attachment: &amp;#39;&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#000">$oDocument&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">GetFileName&lt;/span>&lt;span style="color:#000;font-weight:bold">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">else&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$oLog&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">AddLogEntry&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;Removed attachment: &amp;#39;&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">.&lt;/span>&lt;span style="color:#000">$oDocument&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">GetFileName&lt;/span>&lt;span style="color:#000;font-weight:bold">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 将修改后的日志设置回当前 UserRequest
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Set&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;public_log&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">$oLog&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">DBUpdate&lt;/span>&lt;span style="color:#000;font-weight:bold">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="订阅事件">订阅事件&lt;/h2>
&lt;p>这里我们订阅了 2 个不同的事件，但使用相同的回调方法来处理：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;UserRequest&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AddLogEntryOnAttachment&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_ADD_ATTACHMENT_TO_OBJECT&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>AddLogEntryOnAttachment&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AddLogEntryOnAttachmentRemoval&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_REMOVE_ATTACHMENT_FROM_OBJECT&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>AddLogEntryOnAttachment&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="完整增量">完整增量&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;itop_design&lt;/span> &lt;span style="color:#c4a000">xmlns:xsi=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span> &lt;span style="color:#c4a000">version=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;3.1&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;classes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;UserRequest&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AddLogEntryOnAttachment&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_ADD_ATTACHMENT_TO_OBJECT&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>AddLogEntryOnAttachment&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AddLogEntryOnAttachmentRemoval&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_REMOVE_ATTACHMENT_FROM_OBJECT&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>AddLogEntryOnAttachment&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>0&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;methods&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;method&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;AddLogEntryOnAttachment&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;static&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/static&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;access&amp;gt;&lt;/span>public&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/access&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;type&amp;gt;&lt;/span>EventListener&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/type&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;code&amp;gt;&lt;/span>&lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[ public function AddLogEntryOnAttachment(Combodo\iTop\Service\Events\EventData $oEventData) { blablabla... } ]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/code&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/method&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/methods&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/classes&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/itop_design&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="itop-310-但低于-312-的替代方案">iTop 3.1.0+ 但低于 3.1.2 的替代方案&lt;/h2>
&lt;p>在 iTop 3.1.0+ 但低于 3.1.2 的版本中，可以响应 Attachment 类的事件：&lt;/p>
&lt;ul>
&lt;li>&lt;code>EVENT_DB_AFTER_WRITE&lt;/code>&lt;/li>
&lt;li>&lt;code>EVENT_DB_AFTER_DELETE&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>然后检索与附件关联的对象类、对象键，如果是 UserRequest 则添加日志条目。&lt;/p>
&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:log-attachment">https://www.itophub.io/wiki/page?id=3_2_0:customization:log-attachment&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/log-attachment.txt · Last modified: 2024/09/10 10:25 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 按条件强制字段必填</title><link>/docs/customization/how-to/datamodel/mandatory-field-on-condition/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/mandatory-field-on-condition/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何在特定条件下强制字段必填。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-field-on-condition">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="目标">目标&lt;/h2>
&lt;p>此用例是强制提供字段的一种方式。&lt;/p>
&lt;h2 id="提交前检查">提交前检查&lt;/h2>
&lt;h3 id="仅生产环境中的服务器">仅生产环境中的服务器&lt;/h3>
&lt;p>在此用例中，我们希望确保：&lt;/p>
&lt;ul>
&lt;li>创建时，不提议位置&lt;/li>
&lt;li>修改生产环境中的服务器时，位置变为必填&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;PhysicalDevice&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;location_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;!-- 如果状态更改，强制重新计算 location_id 标志 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;dependencies&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redefine&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;org_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;attribute&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;status&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/dependencies&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Server&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;evtSetInitialFlags&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;!-- 事件 ID 不需要与函数名相同，但也可以相同 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_SET_INITIAL_ATTRIBUTES_FLAGS&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;!-- 回调必须是现有类方法的名称。名称自由 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>evtSetInitialFlags&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;evtSetAttributeFlags&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_SET_ATTRIBUTES_FLAGS&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>evtSetAttributeFlags&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;methods&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;method&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;evtSetInitialFlags&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;static&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/static&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;access&amp;gt;&lt;/span>public &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/access&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;comment&amp;gt;&lt;/span>此方法在打开服务器创建表单之前调用一次&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/comment&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;code&amp;gt;&lt;/span>&lt;span style="color:#a40000">&amp;lt;&lt;/span>![CDATA[
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">evtSetInitialAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span> &lt;span style="color:#8f5902;font-style:italic">// 强制标志，忽略现有标志
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ForceInitialAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;location_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">OPT_ATT_HIDDEN&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// $this-&amp;gt;AddInitialAttributeFlags(&amp;#39;location_id&amp;#39;, OPT_ATT_HIDDEN); 如果其他代码也强制将其设为必填，可能不起作用
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">evtSetAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">((&lt;/span>&lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">IsValidAttCode&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">get_class&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;status&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;status&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;production&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span> &lt;span style="color:#8f5902;font-style:italic">// 添加必填标志
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">AddAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;location_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">OPT_ATT_MANDATORY&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 可以决定设置此标志并忽略已为该属性设置的其他标志
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#8f5902;font-style:italic">// 在这种情况下，使用 ForceAttributeFlags 代替 AddAttributeFlags
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ForceAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;location_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">OPT_ATT_MANDATORY&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="仅生产环境中的服务器和网络设备">仅生产环境中的服务器和网络设备&lt;/h3>
&lt;p>将上述事件和方法分别在 Server 和 NetworkDevice 类上声明两次。&lt;/p>
&lt;h3 id="仅生产环境中的数据中心设备">仅生产环境中的数据中心设备&lt;/h3>
&lt;p>将上述事件和方法在 DatacenterDevice 类上声明，而不是 Server 类。&lt;/p>
&lt;h2 id="提交时检查">提交时检查&lt;/h2>
&lt;p>我们也可以在提交时检查是否提供了位置，如果没有，则阻止创建/修改并显示错误消息，以便用户填写位置后再次提交。&lt;/p>
&lt;p>订阅 &lt;code>EVENT_DB_CHECK_TO_WRITE&lt;/code> 事件，并定义对象类的回调方法 &lt;code>evtCheckToWrite()&lt;/code>：&lt;/p>
&lt;ul>
&lt;li>此事件在写入数据库之前生成&lt;/li>
&lt;li>如果遇到数据不一致，回调方法应提供错误消息。错误消息使用 &lt;code>$this-&amp;gt;AddCheckIssue('Some Error Message')&lt;/code> 生成，警告消息使用 &lt;code>$this-&amp;gt;AddCheckWarning('Some Warning Message')&lt;/code>&lt;/li>
&lt;li>从此方法返回时，如果至少有一个错误，对象不会写入数据库（创建或更新）&lt;/li>
&lt;li>错误和警告消息仅在交互模式下显示给用户：控制台、门户、CSV 导入&lt;/li>
&lt;li>对于数据同步、REST/JSON、CLI，根据跟踪级别记录在 &lt;code>itop/log/error.log&lt;/code> 中&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>迁移注意：&lt;/strong> 在设置上没有可见效果，但不符合规范的对象不能再被修改，直到它们变得合规。因此可能会阻止数据同步或 REST/JSON 脚本更新其他字段。要识别有问题的对象，请创建一个审计规则来检索不符合此新约束的对象，并在 UI 中或通过 CSV 导入逐一修复。&lt;/p>
&lt;p>在 iTop 3.1.0 之前，可以使用扩展性 API，将相同代码放入 &lt;code>iApplicationObjectExtension::OnCheckToWrite()&lt;/code> 中。&lt;/p>
&lt;p>在此用例中，我们希望阻止服务器在未提供位置的情况下被设置为 &amp;ldquo;production&amp;rdquo; 状态。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Server&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;evtCheckToWrite&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_CHECK_TO_WRITE&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>evtCheckToWrite&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">evtCheckToWrite&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// 防御性编程，确保 &amp;#39;status&amp;#39; 是当前类上的现有字段
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#8f5902;font-style:italic">// 然后检查条件：枚举值返回代码而非标签，因此我们测试代码
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">IsValidAttCode&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">get_class&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;status&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;status&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;production&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// AttributeExternalKey 永远不会为 NULL，0 是空值时使用的值
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">MetaModel&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">IsValidAttCode&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">get_class&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#000;font-weight:bold">),&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;location_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ce5c00;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;location_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">==&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span>&lt;span style="color:#000;font-weight:bold">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">// &amp;#39;Server:Error:LocationMandatoryInProduction&amp;#39; 必须声明为字典条目
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">AddCheckIssue&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Dict&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">::&lt;/span>&lt;span style="color:#c4a000">Format&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;Server:Error:LocationMandatoryInProduction&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>也可以直接提供简单的纯文本错误消息：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">AddCheckIssue&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;Location is mandatory for all Servers in production&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在 XML 中定义字典条目的方式：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;entry&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Server:Error:LocationMandatoryInProduction&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#8f5902;font-style:italic">&amp;lt;![CDATA[&amp;#39;Location is mandatory for all Servers in production&amp;#39;]]&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/entry&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-field-on-condition">https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-field-on-condition&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/mandatory-field-on-condition.txt · Last modified: 2025/05/21 10:58 by 127.0.0.1&lt;/p></description></item><item><title>Docs: 仅对子类强制字段必填</title><link>/docs/customization/how-to/datamodel/mandatory-field-subclass/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0000</pubDate><guid>/docs/customization/how-to/datamodel/mandatory-field-subclass/</guid><description>
&lt;div class="pageinfo pageinfo-primary">
&lt;p>本文档介绍如何仅在子类上强制字段必填。更多详细内容请参考 &lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-field-subclass">iTop 官方文档&lt;/a>。&lt;/p>
&lt;/div>
&lt;h2 id="目标">目标&lt;/h2>
&lt;p>此用例是强制提供字段的一种方式。&lt;/p>
&lt;h3 id="数据中心设备必填">数据中心设备必填&lt;/h3>
&lt;p>在此用例中，我们希望 &lt;code>PhysicalDevice&lt;/code> 类上声明的 &lt;code>location_id&lt;/code> 字段仅在 &lt;code>DatacenterDevice&lt;/code> 上必填。总结如下：&lt;/p>
&lt;ul>
&lt;li>在 DatacenterDevice 下的所有类上位置必须必填：NAS、网络设备、SAN 交换机、服务器、存储系统、磁带库&lt;/li>
&lt;li>在所有其他 PhysicalDevice 子类上位置保持可选，例如手机&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>注意：&lt;/strong> 在标准数据模型中，&lt;code>DatacenterDevice&lt;/code> 是 &lt;code>PhysicalDevice&lt;/code> 的子类之一，&lt;code>location_id&lt;/code> 在 PhysicalDevice 上是可选字段。&lt;/p>
&lt;p>此情况比较棘手，因为 iTop 数据模型不允许在子类上覆盖父类定义的属性。&lt;code>location_id&lt;/code> 字段在 &lt;code>PhysicalDevice&lt;/code> 类上声明，而 &lt;code>DatacenterDevice&lt;/code> 是 &lt;code>PhysicalDevice&lt;/code> 的子类。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;DatacenterDevice&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;field&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;location_id&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;is_null_allowed&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;redefine&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>false&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/is_null_allowed&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/field&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/fields&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>为解决此用例，我们必须订阅 2 个事件：一个用于&amp;quot;创建表单&amp;quot;，一个用于&amp;quot;修改表单&amp;quot;。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Server&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;must_exist&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;evtSetCreationFlags&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_SET_INITIAL_ATTRIBUTES_FLAGS&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>evtSetCreationFlags&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;evtSetModificationFlags&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_SET_ATTRIBUTES_FLAGS&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>evtSetModificationFlags&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我们在创建时强制要求提供位置，并在修改时阻止移除位置。位置仍可在对象修改表单中更改。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">evtSetCreationFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span> &lt;span style="color:#8f5902;font-style:italic">// 注意：创建时调用的方法与修改时不同
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ForceInitialAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;location_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">OPT_ATT_MANDATORY&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">evtSetModificationFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span> &lt;span style="color:#8f5902;font-style:italic">// 注意：修改时调用的方法与创建时不同
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic">&lt;/span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ForceAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;location_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">OPT_ATT_MANDATORY&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>迁移注意：&lt;/strong> 在设置上没有可见效果，但不符合规范的对象不能再在控制台或门户中修改，直到提供了位置。创建一个审计规则来检索不符合此新约束的对象并修复它们。&lt;/p>
&lt;h3 id="仅服务器和网络设备">仅服务器和网络设备&lt;/h3>
&lt;p>在此用例中，我们希望 &lt;code>location_id&lt;/code> 字段仅对 Server 和 NetworkDevice 必填，而对 PhysicalDevice 的其他子类不是必填。&lt;/p>
&lt;p>解决方案与上述情况类似，只需在 &lt;code>PhysicalDevice&lt;/code> 类上声明上述方法，并在每个 &lt;code>Server&lt;/code> 和 &lt;code>NetworkDevice&lt;/code> 类上订阅事件。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">evtSetCreationFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ForceInitialAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;location_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">OPT_ATT_MANDATORY&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">public&lt;/span> &lt;span style="color:#204a87;font-weight:bold">function&lt;/span> &lt;span style="color:#000">evtSetModificationFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">Combodo\iTop\Service\Events\EventData&lt;/span> &lt;span style="color:#000">$oEventData&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">ForceAttributeFlags&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;location_id&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span> &lt;span style="color:#000">OPT_ATT_MANDATORY&lt;/span>&lt;span style="color:#000;font-weight:bold">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000;font-weight:bold">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;Server&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;evtSetCreationFlags&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_SET_INITIAL_ATTRIBUTES_FLAGS&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>evtSetCreationFlags&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;evtSetModificationFlags&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_SET_ATTRIBUTES_FLAGS&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>evtSetModificationFlags&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;class&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;NetworkDevice&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;evtSetCreationFlags&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_SET_INITIAL_ATTRIBUTES_FLAGS&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>evtSetCreationFlags&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event_listener&lt;/span> &lt;span style="color:#c4a000">id=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;evtSetModificationFlags&amp;#34;&lt;/span> &lt;span style="color:#c4a000">_delta=&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;define&amp;#34;&lt;/span>&lt;span style="color:#204a87;font-weight:bold">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;event&amp;gt;&lt;/span>EVENT_DB_SET_ATTRIBUTES_FLAGS&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;rank&amp;gt;&lt;/span>10&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/rank&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;callback&amp;gt;&lt;/span>evtSetModificationFlags&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/callback&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listener&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#204a87;font-weight:bold">&amp;lt;/event_listeners&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">&amp;lt;/class&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="所有数据中心设备但磁带库除外">所有数据中心设备，但磁带库除外&lt;/h3>
&lt;p>此用例：我们希望 &lt;code>location_id&lt;/code> 字段对所有 &lt;code>DatacenterDevice&lt;/code> 必填，但磁带库除外。&lt;/p>
&lt;p>解决方案与上述情况类似，只需在 &lt;code>DatacenterDevice&lt;/code> 类上声明上述方法，并在函数中测试最终类是否不是 &lt;code>TapeLibrary&lt;/code>。&lt;/p>
&lt;p>以下是在 PHP 方法中获取和测试最终类值的方法：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">if&lt;/span> &lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#000">$this&lt;/span>&lt;span style="color:#ce5c00;font-weight:bold">-&amp;gt;&lt;/span>&lt;span style="color:#c4a000">Get&lt;/span>&lt;span style="color:#000;font-weight:bold">(&lt;/span>&lt;span style="color:#4e9a06">&amp;#39;finalclass&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">!=&lt;/span> &lt;span style="color:#4e9a06">&amp;#39;TapeLibrary&amp;#39;&lt;/span>&lt;span style="color:#000;font-weight:bold">)&lt;/span> &lt;span style="color:#000;font-weight:bold">{&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>原文：&lt;a href="https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-field-subclass">https://www.itophub.io/wiki/page?id=3_2_0:customization:mandatory-field-subclass&lt;/a>&lt;/p>
&lt;p>版本：3_2_0/customization/mandatory-field-subclass.txt · Last modified: 2025/05/21 10:59 by 127.0.0.1&lt;/p></description></item></channel></rss>