r3014 - getPortTypes(): sayonara
authorDenis Ovsienko <infrastation@yandex.ru>
Wed, 29 Jul 2009 14:31:53 +0000 (14:31 +0000)
committerDenis Ovsienko <infrastation@yandex.ru>
Wed, 29 Jul 2009 14:31:53 +0000 (14:31 +0000)
 - getObjectTypeList(): sayonara
 - getDict(): sayonara
 - readChapter(): new spec, now with optional filtering
 - decodeObjectType(): function instead of cell key
 - getAttrValues(): no more second argument, but also return "chapter_id"
 - savePortMap(): update accordingly
 - renderEditObjectForm(): idem
 - renderRackObject(): idem
 - renderPortsForObject(): idem
 - renderAddMultipleObjectsForm(): idem
 - renderPortMap(): idem
 - renderAttributes(): idem
 - renderEditAttributesForm(): idem
 - renderEditAttrMapForm(): idem
 - renderAutoPortsForm(): idem
 - getSwitchVLANs(): idem
 - setSwitchVLANs(): idem
 - renderChapter(): idem
 - renderChapterEditor(): idem
 - getRackspaceHistory(): only SELECT from MountOperation
 - getAttrMap(): drop "objtype_name" from result
 - renderRackspaceHistory(): use cell functions, don't decode data locally
 - getChapterRefc(): new function to hold refc computation from getDict()
 - setDisplayedName(): employ decodeObjectType()
 - findAllEndpoints(): use attribute id instead of name
 - parseWikiLink(): don't accept "strip_optgroup", but decide from "which"

inc/config.php
inc/database.php
inc/functions.php
inc/gateways.php
inc/interface.php
inc/ophandlers.php

index d7b1e739cbeef383a47122c4ca2984f1d844a863..3dcaf7b1360626b8a38c658451c966c3adcb039c 100644 (file)
@@ -13,6 +13,8 @@
 // Current code version is subject to change with each new release.
 define ('CODE_VERSION', '0.17.2');
 define ('MAX_DICT_KEY', 1150);
+define ('CHAP_OBJTYPE', 1);
+define ('CHAP_PORTTYPE', 2);
 
 define ('TAGNAME_REGEXP', '^[[:alnum:]]([\. _~-]?[[:alnum:]])*$');
 define ('AUTOTAGNAME_REGEXP', '^\$[[:alnum:]]([\. _~-]?[[:alnum:]])*$');
index aa1f87a79753c5cd85c16f6067586fef6720371c..00c47e6d6be56acf8e7802f82103461ec627220e 100644 (file)
@@ -22,7 +22,6 @@ $SQLSchema = array
                        'Rack_name' => '(select name from Rack where id = rack_id)',
                        'row_id' => '(select row_id from Rack where id = rack_id)',
                        'Row_name' => '(select name from RackRow where id = row_id)',
-                       'objtype_name' => '(select dict_value from Dictionary where dict_key = objtype_id)',
                        'has_problems' => 'has_problems',
                        'comment' => 'comment',
                        'nports' => '(SELECT COUNT(*) FROM Port WHERE object_id = RackObject.id)',
@@ -227,13 +226,6 @@ function commitDeleteRow($rackrow_id)
        return TRUE;
 }
 
-// This function returns id->name map for all object types. The map is used
-// to build <select> input for objects.
-function getObjectTypeList ()
-{
-       return readChapter ('RackObjectType');
-}
-
 // Return a simple object list w/o related information, so that the returned value
 // can be directly used by printSelect(). An optional argument is the name of config
 // option with constraint in RackCode.
@@ -519,15 +511,10 @@ function amplifyCell (&$record, $dummy = NULL)
        }
 }
 
-function getPortTypes ()
-{
-       return readChapter ('PortType');
-}
-
 function getObjectPortsAndLinks ($object_id)
 {
        // prepare decoder
-       $ptd = readChapter ('PortType');
+       $ptd = readChapter (CHAP_PORTTYPE, 'a');
        $query = "select id, name, label, l2address, type as type_id, reservation_comment from Port where object_id = ${object_id}";
        // list and decode all ports of the current object
        $result = useSelectBlade ($query, __FUNCTION__);
@@ -903,14 +890,10 @@ function recordHistory ($tableName, $whereClause)
 function getRackspaceHistory ()
 {
        $query =
-               "select mo.id as mo_id, ro.id as ro_id, ro.name, mo.ctime, mo.comment, dict_value as objtype_name, user_name from " .
-               "MountOperation as mo inner join RackObject as ro on mo.object_id = ro.id " .
-               "inner join Dictionary on objtype_id = dict_key join Chapter on Chapter.id = Dictionary.chapter_id " .
-               "where Chapter.name = 'RackObjectType' order by ctime desc";
+               "SELECT id as mo_id, object_id as ro_id, ctime, comment, user_name FROM " .
+               "MountOperation ORDER BY ctime DESC";
        $result = useSelectBlade ($query, __FUNCTION__);
-       $ret = $result->fetchAll(PDO::FETCH_ASSOC);
-       $result->closeCursor();
-       return $ret;
+       return $result->fetchAll (PDO::FETCH_ASSOC);
 }
 
 // This function is used in renderRackspaceHistory()
@@ -1859,67 +1842,6 @@ function addPortCompat ($type1 = 0, $type2 = 0)
        );
 }
 
-// This function returns the dictionary as an array of trees, each tree
-// representing a single chapter. Each element has 'id', 'name', 'sticky'
-// and 'word' keys with the latter holding all the words within the chapter.
-// FIXME: there's a lot of excess legacy code in this function, it's reasonable
-// to merge it with readChapter().
-function getDict ($parse_links = FALSE)
-{
-       $query =
-               "select Chapter.name as chapter_name, Chapter.id as chapter_no, dict_key, dict_value, sticky from " .
-               "Chapter left join Dictionary on Chapter.id = Dictionary.chapter_id order by Chapter.name, dict_value";
-       $result = useSelectBlade ($query, __FUNCTION__);
-       $dict = array();
-       while ($row = $result->fetch (PDO::FETCH_ASSOC))
-       {
-               $chapter_no = $row['chapter_no'];
-               if (!isset ($dict[$chapter_no]))
-               {
-                       $dict[$chapter_no]['no'] = $chapter_no;
-                       $dict[$chapter_no]['name'] = $row['chapter_name'];
-                       $dict[$chapter_no]['sticky'] = $row['sticky'] == 'yes' ? TRUE : FALSE;
-                       $dict[$chapter_no]['word'] = array();
-               }
-               if ($row['dict_key'] != NULL)
-               {
-                       $dict[$chapter_no]['word'][$row['dict_key']] = ($parse_links or $row['dict_key'] <= MAX_DICT_KEY) ?
-                               parseWikiLink ($row['dict_value'], 'a') : $row['dict_value'];
-                       $dict[$chapter_no]['refcnt'][$row['dict_key']] = 0;
-               }
-       }
-       unset ($result);
-       // Find the list of all assigned values of dictionary-addressed attributes, each with
-       // chapter/word keyed reference counters. Use the structure to adjust reference counters
-       // of the returned disctionary words.
-       $query = "select a.id as attr_id, am.chapter_id as chapter_no, uint_value, count(object_id) as refcnt " .
-               "from Attribute as a inner join AttributeMap as am on a.id = am.attr_id " .
-               "inner join AttributeValue as av on a.id = av.attr_id " .
-               "inner join Dictionary as d on am.chapter_id = d.chapter_id and av.uint_value = d.dict_key " .
-               "where a.type = 'dict' group by a.id, am.chapter_id, uint_value " .
-               "order by a.id, am.chapter_id, uint_value";
-       $result = useSelectBlade ($query, __FUNCTION__);
-       while ($row = $result->fetch (PDO::FETCH_ASSOC))
-               $dict[$row['chapter_no']]['refcnt'][$row['uint_value']] = $row['refcnt'];
-       unset ($result);
-       // PortType chapter is referenced by PortCompat and Port tables
-       $query = 'select dict_key as uint_value, chapter_id as chapter_no, (select count(*) from PortCompat where type1 = dict_key or type2 = dict_key) + ' .
-               '(select count(*) from Port where type = dict_key) as refcnt ' .
-               'from Dictionary where chapter_id = 2';
-       $result = useSelectBlade ($query, __FUNCTION__);
-       while ($row = $result->fetch (PDO::FETCH_ASSOC))
-               $dict[$row['chapter_no']]['refcnt'][$row['uint_value']] = $row['refcnt'];
-       unset ($result);
-       // RackObjectType chapter is referenced by AttributeMap and RackObject tables
-       $query = 'select dict_key as uint_value, chapter_id as chapter_no, (select count(*) from AttributeMap where objtype_id = dict_key) + ' .
-               '(select count(*) from RackObject where objtype_id = dict_key) as refcnt from Dictionary where chapter_id = 1';
-       $result = useSelectBlade ($query, __FUNCTION__);
-       while ($row = $result->fetch (PDO::FETCH_ASSOC))
-               $dict[$row['chapter_no']]['refcnt'][$row['uint_value']] = $row['refcnt'];
-       unset ($result);
-       return $dict;
-}
-
 function getDictStats ()
 {
        $stock_chapters = array (1, 2, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27);
@@ -2124,31 +2046,63 @@ function commitDeleteChapter ($chapter_no = 0)
 
 // This is a dictionary accessor. We perform link rendering, so the user sees
 // nice <select> drop-downs.
-function readChapter ($chapter_name = '')
+function readChapter ($chapter_id = 0, $style = '')
 {
-       if (!strlen ($chapter_name))
-               throw new InvalidArgException ('$chapter_name', $chapter_name);
+       if ($chapter_id <= 0)
+               throw new InvalidArgException ('$chapter_id', $chapter_id);
        $query =
-               "select dict_key, dict_value from Dictionary join Chapter on Chapter.id = Dictionary.chapter_id " .
-               "where Chapter.name = '${chapter_name}'";
+               "select dict_key, dict_value from Dictionary " .
+               "where chapter_id = ${chapter_id}";
        $result = useSelectBlade ($query, __FUNCTION__);
        $chapter = array();
        while ($row = $result->fetch (PDO::FETCH_ASSOC))
-               $chapter[$row['dict_key']] = parseWikiLink ($row['dict_value'], 'o');
+               $chapter[$row['dict_key']] = $style == '' ? $row['dict_value'] : parseWikiLink ($row['dict_value'], $style);
        $result->closeCursor();
        // SQL ORDER BY had no sense, because we need to sort after link rendering, not before.
        asort ($chapter);
        return $chapter;
 }
 
+// Return refcounters for all given keys of the given chapter.
+function getChapterRefc ($chapter_id, $keylist)
+{
+       $ret = array_fill_keys ($keylist, 0);
+       switch ($chapter_id)
+       {
+       case CHAP_OBJTYPE:
+               // RackObjectType chapter is referenced by AttributeMap and RackObject tables
+               $query = 'select dict_key as uint_value, (select count(*) from AttributeMap where objtype_id = dict_key) + ' .
+                       "(select count(*) from RackObject where objtype_id = dict_key) as refcnt from Dictionary where chapter_id = ${chapter_id}";
+               break;
+       case CHAP_PORTTYPE:
+               // PortType chapter is referenced by PortCompat and Port tables
+               $query = 'select dict_key as uint_value, (select count(*) from PortCompat where type1 = dict_key or type2 = dict_key) + ' .
+                       '(select count(*) from Port where type = dict_key) as refcnt ' .
+                       "from Dictionary where chapter_id = ${chapter_id}";
+               break;
+       default:
+               // Find the list of all assigned values of dictionary-addressed attributes, each with
+               // chapter/word keyed reference counters.
+               $query = "select uint_value, count(object_id) as refcnt " .
+                       "from Attribute as a inner join AttributeMap as am on a.id = am.attr_id " .
+                       "inner join AttributeValue as av on a.id = av.attr_id " .
+                       "inner join Dictionary as d on am.chapter_id = d.chapter_id and av.uint_value = d.dict_key " .
+                       "where a.type = 'dict' and am.chapter_id = ${chapter_id} group by uint_value";
+               break;
+       }
+       $result = useSelectBlade ($query, __FUNCTION__);
+       while ($row = $result->fetch (PDO::FETCH_ASSOC))
+               $ret[$row['uint_value']] = $row['refcnt'];
+       return $ret;
+}
+
 // Return a list of all stickers with sticker map applied. Each sticker records will
 // list all its ways on the map with refcnt set.
 function getAttrMap ()
 {
        $query =
                'SELECT id, type, name, chapter_id, (SELECT name FROM Chapter WHERE id = chapter_id) ' .
-               'AS chapter_name, objtype_id, (SELECT dict_value FROM Dictionary WHERE dict_key = objtype_id) ' .
-               'AS objtype_name, (SELECT COUNT(object_id) FROM AttributeValue AS av INNER JOIN RackObject AS ro ' .
+               'AS chapter_name, objtype_id, (SELECT COUNT(object_id) FROM AttributeValue AS av INNER JOIN RackObject AS ro ' .
                'ON av.object_id = ro.id WHERE av.attr_id = Attribute.id AND ro.objtype_id = AttributeMap.objtype_id) ' .
                'AS refcnt FROM Attribute LEFT JOIN AttributeMap ON id = attr_id ORDER BY Attribute.name, objtype_id';
        $result = useSelectBlade ($query, __FUNCTION__);
@@ -2168,7 +2122,6 @@ function getAttrMap ()
                $application = array
                (
                        'objtype_id' => $row['objtype_id'],
-                       'objtype_name' => $row['objtype_name'],
                        'refcnt' => $row['refcnt'],
                );
                if ($row['type'] == 'dict')
@@ -2279,7 +2232,7 @@ function commitReduceAttrMap ($attr_id = 0, $objtype_id)
 // This function returns all optional attributes for requested object
 // as an array of records. NULL is returned on error and empty array
 // is returned, if there are no attributes found.
-function getAttrValues ($object_id, $strip_optgroup = FALSE)
+function getAttrValues ($object_id)
 {
        if ($object_id <= 0)
        {
@@ -2289,7 +2242,7 @@ function getAttrValues ($object_id, $strip_optgroup = FALSE)
        $ret = array();
        $query =
                "select A.id as attr_id, A.name as attr_name, A.type as attr_type, C.name as chapter_name, " .
-               "AV.uint_value, AV.float_value, AV.string_value, D.dict_value from " .
+               "C.id as chapter_id, AV.uint_value, AV.float_value, AV.string_value, D.dict_value from " .
                "RackObject as RO inner join AttributeMap as AM on RO.objtype_id = AM.objtype_id " .
                "inner join Attribute as A on AM.attr_id = A.id " .
                "left join AttributeValue as AV on AV.attr_id = AM.attr_id and AV.object_id = RO.id " .
@@ -2305,18 +2258,18 @@ function getAttrValues ($object_id, $strip_optgroup = FALSE)
                $record['type'] = $row['attr_type'];
                switch ($row['attr_type'])
                {
+                       case 'dict':
+                               $record['chapter_id'] = $row['chapter_id'];
+                               $record['chapter_name'] = $row['chapter_name'];
+                               $record['key'] = $row['uint_value'];
+                               // fall through
                        case 'uint':
                        case 'float':
                        case 'string':
                                $record['value'] = $row[$row['attr_type'] . '_value'];
+                               $record['o_value'] = parseWikiLink ($record['value'], 'o');
                                $record['a_value'] = parseWikiLink ($record['value'], 'a');
                                break;
-                       case 'dict':
-                               $record['value'] = parseWikiLink ($row[$row['attr_type'] . '_value'], 'o', $strip_optgroup);
-                               $record['a_value'] = parseWikiLink ($row[$row['attr_type'] . '_value'], 'a', $strip_optgroup);
-                               $record['chapter_name'] = $row['chapter_name'];
-                               $record['key'] = $row['uint_value'];
-                               break;
                        default:
                                $record['value'] = NULL;
                                break;
index a186187e2e5e4117e712c4f0d72cd32c28a26688..ce97454dfc3118f70b0027ed47c0e60f2d98405b 100644 (file)
@@ -203,9 +203,9 @@ function setDisplayedName (&$cell)
        {
                $cell['atags'][] = array ('tag' => '$nameless');
                if (considerConfiguredConstraint ($cell, 'NAMEWARN_LISTSRC'))
-                       $cell['dname'] = 'ANONYMOUS ' . $cell['objtype_name'];
+                       $cell['dname'] = 'ANONYMOUS ' . decodeObjectType ($cell['objtype_id'], 'o');
                else
-                       $cell['dname'] = '[' . $cell['objtype_name'] . ']';
+                       $cell['dname'] = '[' . decodeObjectType ($cell['objtype_id'], 'o') . ']';
        }
 }
 
@@ -705,9 +705,8 @@ function buildPortCompatMatrixFromList ($portTypeList, $portCompatList)
 // object is returned (which may appear 0 and more elements long).
 function findAllEndpoints ($object_id, $fallback = '')
 {
-       $values = getAttrValues ($object_id);
-       foreach ($values as $record)
-               if ($record['name'] == 'FQDN' && strlen ($record['value']))
+       foreach (getAttrValues ($object_id) as $record)
+               if ($record['id'] == 3 && strlen ($record['value'])) // FQDN
                        return array ($record['value']);
        $regular = array();
        foreach (getObjectIPv4Allocations ($object_id) as $dottedquad => $alloc)
@@ -725,11 +724,13 @@ function findAllEndpoints ($object_id, $fallback = '')
 // 3. [[word word word | URL]]
 // This function parses the line and returns text suitable for either A
 // (rendering <A HREF>) or O (for <OPTION>).
-function parseWikiLink ($line, $which, $strip_optgroup = FALSE)
+function parseWikiLink ($line, $which)
 {
        if (preg_match ('/^\[\[.+\]\]$/', $line) == 0)
        {
-               if ($strip_optgroup)
+               // always strip the marker for A-data, but let cookOptgroup()
+               // do this later (otherwise it can't sort groups out)
+               if ($which == 'a')
                        return ereg_replace ('^.+%GSKIP%', '', ereg_replace ('^(.+)%GPASS%', '\\1 ', $line));
                else
                        return $line;
@@ -737,13 +738,11 @@ function parseWikiLink ($line, $which, $strip_optgroup = FALSE)
        $line = preg_replace ('/^\[\[(.+)\]\]$/', '$1', $line);
        $s = explode ('|', $line);
        $o_value = trim ($s[0]);
-       if ($strip_optgroup)
-               $o_value = ereg_replace ('^.+%GSKIP%', '', ereg_replace ('^(.+)%GPASS%', '\\1 ', $o_value));
-       $a_value = trim ($s[1]);
-       if ($which == 'a')
-               return "<a href='${a_value}'>${o_value}</a>";
        if ($which == 'o')
                return $o_value;
+       $o_value = ereg_replace ('^.+%GSKIP%', '', ereg_replace ('^(.+)%GPASS%', '\\1 ', $o_value));
+       $a_value = trim ($s[1]);
+       return "<a href='${a_value}'>${o_value}</a>";
 }
 
 // rackspace usage for a single rack
@@ -2143,4 +2142,17 @@ function getTagChart ($limit = 0, $realm = 'total', $special_tags = array())
        return $ret;
 }
 
+function decodeObjectType ($objtype_id, $style = 'r')
+{
+       static $types = array();
+       if (!count ($types))
+               $types = array
+               (
+                       'r' => readChapter (CHAP_OBJTYPE),
+                       'a' => readChapter (CHAP_OBJTYPE, 'a'),
+                       'o' => readChapter (CHAP_OBJTYPE, 'o')
+               );
+       return $types[$style][$objtype_id];
+}
+
 ?>
index 48ec836d4f82fa9022cb14ae2579b8426db521a7..4e0595ddb9b96144ef2e57c5d1d452b0e2652f10 100644 (file)
@@ -86,7 +86,7 @@ function getSwitchVLANs ($object_id = 0)
                return NULL;
        }
        $hwtype = $swtype = 'unknown';
-       foreach (getAttrValues ($object_id, TRUE) as $record)
+       foreach (getAttrValues ($object_id) as $record)
        {
                if ($record['name'] == 'SW type' && strlen ($record['value']))
                        $swtype = str_replace (' ', '+', $record['value']);
@@ -166,7 +166,7 @@ function setSwitchVLANs ($object_id = 0, $setcmd)
        if (count ($endpoints) > 1)
                return oneLiner (162); // can't pick an address
        $hwtype = $swtype = 'unknown';
-       foreach (getAttrValues ($object_id, TRUE) as $record)
+       foreach (getAttrValues ($object_id) as $record)
        {
                if ($record['name'] == 'SW type' && strlen ($record['value']))
                        $swtype = strtr ($record['value'], ' ', '+');
index 1a38c887839787e8409d03d53832f5860b0805a4..7314581e1cb1fe9aa15d9d7535e23c7d8a277977 100644 (file)
@@ -558,7 +558,7 @@ function renderEditObjectForm ($object_id)
        echo '<table border=0 cellspacing=0 cellpadding=3 align=center>';
        echo "<tr><td>&nbsp;</td><th colspan=2><h2>Attributes</h2></th></tr>";
        echo "<tr><td>&nbsp;</td><th class=tdright>Type:</th><td class=tdleft>";
-       printSelect (getObjectTypeList(), 'object_type_id', $object['objtype_id']);
+       printNiftySelect (cookOptgroups (readChapter (CHAP_OBJTYPE, 'o')), 'object_type_id', $object['objtype_id']);
        echo "</td></tr>\n";
        // baseline info
        echo "<tr><td>&nbsp;</td><th class=tdright>Common name:</th><td class=tdleft><input type=text name=object_name value='${object['name']}'></td></tr>\n";
@@ -593,7 +593,7 @@ function renderEditObjectForm ($object_id)
                                        echo "<input type=text name=${i}_value value='${record['value']}'>";
                                        break;
                                case 'dict':
-                                       $chapter = readChapter ($record['chapter_name']);
+                                       $chapter = readChapter ($record['chapter_id'], 'o');
                                        $chapter[0] = '-- NOT SET --';
                                        $chapter = cookOptgroups ($chapter, $object['objtype_id'], $record['key']);
                                        printNiftySelect ($chapter, "${i}_value", $record['key']);
@@ -795,7 +795,7 @@ function renderRackObject ($object_id)
                'tab' => 'default',
                'cfe' => '{$typeid_' . $info['objtype_id'] . '}'
        ));
-       echo "'>${info['objtype_name']}</a></td></tr>\n";
+       echo "'>" . decodeObjectType ($info['objtype_id'], 'o') . '</a></td></tr>';
        if (strlen ($info['asset_no']))
                echo "<tr><th width='50%' class=tdright>Asset tag:</th><td class=tdleft>${info['asset_no']}</td></tr>\n";
        // FIXME: ditto
@@ -807,7 +807,7 @@ function renderRackObject ($object_id)
                echo "<tr><th width='50%' class=tdright>Barcode:</th><td class=tdleft>${info['barcode']}</td></tr>\n";
        if ($info['has_problems'] == 'yes')
                echo "<tr><td colspan=2 class=msg_error>Has problems</td></tr>\n";
-       foreach (getAttrValues ($object_id, TRUE) as $record)
+       foreach (getAttrValues ($object_id) as $record)
                if (strlen ($record['value']))
                        echo "<tr><th width='50%' class=sticker>${record['name']}:</th><td class=sticker>${record['a_value']}</td></tr>\n";
        printTagTRs
@@ -1076,14 +1076,15 @@ function renderRackMultiSelect ($sname, $racks, $selected)
 // This function renders a form for port edition.
 function renderPortsForObject ($object_id)
 {
-       function printNewItemTR ()
+       $portOptions = cookOptgroups (readChapter (CHAP_PORTTYPE, 'o'));
+       function printNewItemTR ($portOptions)
        {
                printOpFormIntro ('addPort');
                echo "<tr><td>";
                printImageHREF ('add', 'add a port', TRUE);
                echo "</td><td><input type=text size=8 name=port_name tabindex=100></td>\n";
                echo "<td><input type=text size=24 name=port_label tabindex=101></td><td>";
-               printSelect (getPortTypes(), 'port_type_id', getConfigVar ('default_port_type'), 102);
+               printNiftySelect ($portOptions, 'port_type_id', getConfigVar ('default_port_type'), 102);
                echo "<td><input type=text name=port_l2address tabindex=103></td>\n";
                echo "<td colspan=3>&nbsp;</td><td>";
                printImageHREF ('add', 'add a port', TRUE, 104);
@@ -1096,7 +1097,7 @@ function renderPortsForObject ($object_id)
        echo "<tr><th>&nbsp;</th><th>Local name</th><th>Visible label</th><th>Port type</th><th>L2 address</th>";
        echo "<th>Rem. object</th><th>Rem. port</th><th>(Un)link or (un)reserve</th><th>&nbsp;</th></tr>\n";
        if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
-               printNewItemTR();
+               printNewItemTR ($portOptions);
        foreach ($ports as $port)
        {
                printOpFormIntro ('editPort', array ('port_id' => $port['id']));
@@ -1108,7 +1109,7 @@ function renderPortsForObject ($object_id)
                if (!$port['remote_object_id'])
                {
                        echo "<td>";
-                       printSelect (getPortTypes(), 'port_type_id', $port['type_id']);
+                       printNiftySelect ($portOptions, 'port_type_id', $port['type_id']);
                        echo "</td>";
                }
                else
@@ -1160,7 +1161,7 @@ function renderPortsForObject ($object_id)
                echo "</td></form></tr>\n";
        }
        if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
-               printNewItemTR();
+               printNewItemTR ($portOptions);
        echo "</table><br>\n";
        finishPortlet();
 
@@ -1173,7 +1174,7 @@ function renderPortsForObject ($object_id)
        echo '<option value=ssv1>SSV:&lt;interface name&gt; &lt;MAC address&gt;</option>';
        echo "</select>";
        echo 'Default port type: ';
-       printSelect (getPortTypes(), 'port_type', getConfigVar ('default_port_type'), 202);
+       printNiftySelect ($portOptions, 'port_type', getConfigVar ('default_port_type'), 202);
        echo "<input type=submit value='Parse output' tabindex=204><br>\n";
        echo "<textarea name=input cols=100 rows=50 tabindex=203></textarea><br>\n";
        echo '</form>';
@@ -1879,7 +1880,7 @@ function renderRackspaceHistory ()
 
        startPortlet ('Rackspace allocation history');
        echo "<table border=0 cellpadding=5 cellspacing=0 align=center class=cooltable>\n";
-       echo "<tr><th>timestamp</th><th>author</th><th>rack object ID</th><th>rack object type</th><th>rack object name</th><th>comment</th></tr>\n";
+       echo "<tr><th>timestamp</th><th>author</th><th>object</th><th>comment</th></tr>\n";
        foreach ($history as $row)
        {
                if ($row['mo_id'] == $op_id)
@@ -1887,8 +1888,9 @@ function renderRackspaceHistory ()
                else
                        $class = "row_${order}";
                echo "<tr class=${class}><td><a href='".makeHref(array('page'=>$pageno, 'tab'=>$tabno, 'op_id'=>$row['mo_id']))."'>${row['ctime']}</a></td>";
-               echo "<td>${row['user_name']}</td>";
-               echo "<td>${row['ro_id']}</td><td>${row['objtype_name']}</td><td>${row['name']}</td><td>${row['comment']}</td>\n";
+               echo "<td>${row['user_name']}</td><td>";
+               renderCell (spotEntity ('object', $row['ro_id']));
+               echo "</td><td>${row['comment']}</td>\n";
                echo "</tr>\n";
                $order = $nextorder[$order];
        }
@@ -2659,8 +2661,9 @@ function renderNATv4ForObject ($object_id)
 
 function renderAddMultipleObjectsForm ()
 {
-       $typelist = getObjectTypeList();
+       $typelist = readChapter (CHAP_OBJTYPE, 'o');
        $typelist[0] = 'select type...';
+       $typelist = cookOptgroups ($typelist);
        $max = getConfigVar ('MASSCOUNT');
        $tabindex = 100;
 
@@ -2673,7 +2676,7 @@ function renderAddMultipleObjectsForm ()
        {
                echo '<tr><td>';
                // Don't employ DEFAULT_OBJECT_TYPE to avoid creating ghost records for pre-selected empty rows.
-               printSelect ($typelist, "${i}_object_type_id", 0, $tabindex);
+               printNiftySelect ($typelist, "${i}_object_type_id", 0, $tabindex);
                echo '</td>';
                echo "<td><input type=text size=30 name=${i}_object_name tabindex=${tabindex}></td>";
                echo "<td><input type=text size=30 name=${i}_object_label tabindex=${tabindex}></td>";
@@ -3152,7 +3155,7 @@ function renderPortMap ($editable = FALSE)
 {
        global $nextorder;
        startPortlet ("Port compatibility map");
-       $ptlist = getPortTypes();
+       $ptlist = readChapter (CHAP_PORTTYPE, 'a');
        $pclist = getPortCompat();
        $pctable = buildPortCompatMatrixFromList ($ptlist, $pclist);
        if ($editable)
@@ -3241,33 +3244,29 @@ function renderDictionary ()
 function renderChapter ($tgt_chapter_no)
 {
        global $nextorder;
-       foreach (getDict (TRUE) as $chapter_no => $chapter)
+       $words = readChapter ($tgt_chapter_no, 'a');
+       $wc = count ($words);
+       if (!$wc)
        {
-               if ($chapter_no != $tgt_chapter_no)
-                       continue;
-               $wc = count ($chapter['word']);
-               if (!$wc)
-               {
-                       echo "<center><h2>(no records)</h2></center>";
-                       break;
-               }
-               echo "<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
-               echo "<tr><th colspan=3>${wc} record(s)</th></tr>\n";
-               echo "<tr><th>Origin</th><th>Refcnt</th><th>Word</th></tr>\n";
-               $order = 'odd';
-               foreach ($chapter['word'] as $key => $value)
-               {
-                       echo "<tr class=row_${order}><td>";
-                       printImageHREF (($key <= MAX_DICT_KEY) ? 'computer' : 'favorite');
-                       echo '</td><td>';
-                       if ($chapter['refcnt'][$key])
-                               echo $chapter['refcnt'][$key];
-                       echo "</td><td><div title='key=${key}'>${value}</div></td></tr>\n";
-                       $order = $nextorder[$order];
-               }
-               echo "</table>\n<br>";
-               break;
+               echo "<center><h2>(no records)</h2></center>";
+               return;
+       }
+       $refcnt = getChapterRefc ($tgt_chapter_no, array_keys ($words));
+       echo "<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
+       echo "<tr><th colspan=3>${wc} record(s)</th></tr>\n";
+       echo "<tr><th>Origin</th><th>Refcnt</th><th>Word</th></tr>\n";
+       $order = 'odd';
+       foreach ($words as $key => $value)
+       {
+               echo "<tr class=row_${order}><td>";
+               printImageHREF (($key <= MAX_DICT_KEY) ? 'computer' : 'favorite');
+               echo '</td><td>';
+               if ($refcnt[$key])
+                       echo $refcnt[$key];
+               echo "</td><td><div title='key=${key}'>${value}</div></td></tr>\n";
+               $order = $nextorder[$order];
        }
+       echo "</table>\n<br>";
 }
 
 function renderChapterEditor ($tgt_chapter_no)
@@ -3283,51 +3282,44 @@ function renderChapterEditor ($tgt_chapter_no)
                printImageHREF ('add', 'Add new', TRUE, 101);
                echo '</td></tr></form>';
        }
-       $dict = getDict();
        echo "<br><table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
-       foreach ($dict as $chapter_no => $chapter)
+       $words = readChapter ($tgt_chapter_no);
+       $refcnt = getChapterRefc ($tgt_chapter_no, array_keys ($words));
+       $order = 'odd';
+       echo "<tr><th>Origin</th><th>&nbsp;</th><th>Word</th><th>&nbsp;</th></tr>\n";
+       if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
+               printNewItemTR();
+       foreach ($words as $key => $value)
        {
-               if ($chapter_no != $tgt_chapter_no)
+               echo "<tr class=row_${order}><td>";
+               $order = $nextorder[$order];
+               // Show plain row for stock records, render a form for user's ones.
+               if ($key <= MAX_DICT_KEY)
+               {
+                       printImageHREF ('computer');
+                       echo "</td><td>&nbsp;</td><td>${value}</td><td>&nbsp;</td></tr>";
                        continue;
-               $order = 'odd';
-               echo "<tr><th>Origin</th><th>&nbsp;</th><th>Word</th><th>&nbsp;</th></tr>\n";
-               if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
-                       printNewItemTR();
-               foreach ($chapter['word'] as $key => $value)
+               }
+               printOpFormIntro ('upd', array ('dict_key' => $key));
+               printImageHREF ('favorite');
+               echo "</td><td>";
+               // Prevent deleting words currently used somewhere.
+               if ($refcnt[$key])
+                       printImageHREF ('nodelete', 'referenced ' . $refcnt[$key] . ' time(s)');
+               else
                {
-                       echo "<tr class=row_${order}><td>";
-                       // Show plain row for stock records, render a form for user's ones.
-                       if ($key <= MAX_DICT_KEY)
-                       {
-                               printImageHREF ('computer');
-                               echo "</td><td>&nbsp;</td><td>${value}</td><td>&nbsp;</td></tr>";
-                       }
-                       else
-                       {
-                               printOpFormIntro ('upd', array ('dict_key' => $key));
-                               printImageHREF ('favorite');
-                               echo "</td><td>";
-                               // Prevent deleting words currently used somewhere.
-                               if ($chapter['refcnt'][$key])
-                                       printImageHREF ('nodelete', 'referenced ' . $chapter['refcnt'][$key] . ' time(s)');
-                               else
-                               {
-                                       echo "<a href='".makeHrefProcess(array('op'=>'del', 'chapter_no'=>$chapter_no, 'dict_key'=>$key))."'>";
-                                       printImageHREF ('delete', 'Delete word');
-                                       echo "</a>";
-                               }
-                               echo '</td>';
-                               echo "<td class=tdright><input type=text name=dict_value size=64 value='${value}'></td><td>";
-                               printImageHREF ('save', 'Save changes', TRUE);
-                               echo "</td></tr></form>\n";
-                       }
-                       $order = $nextorder[$order];
-               } // foreach ($chapter['word']
-               if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
-                       printNewItemTR();
-               echo "</table>\n";
-               break;
-       } // foreach ($dict
+                       echo "<a href='".makeHrefProcess(array('op'=>'del', 'chapter_no'=>$tgt_chapter_no, 'dict_key'=>$key))."'>";
+                       printImageHREF ('delete', 'Delete word');
+                       echo "</a>";
+               }
+               echo '</td>';
+               echo "<td class=tdright><input type=text name=dict_value size=64 value='${value}'></td><td>";
+               printImageHREF ('save', 'Save changes', TRUE);
+               echo "</td></tr></form>";
+       }
+       if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
+               printNewItemTR();
+       echo "</table>\n";
 }
 
 // We don't allow to rename/delete a sticky chapter and we don't allow
@@ -3391,12 +3383,11 @@ function renderChaptersEditor ()
 function renderAttributes ()
 {
        global $nextorder, $attrtypes;
-       $attrMap = getAttrMap();
        startPortlet ('Optional attributes');
-       echo "<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>\n";
+       echo "<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>";
        echo "<tr><th class=tdleft>Attribute name</th><th class=tdleft>Attribute type</th><th class=tdleft>Applies to</th></tr>";
        $order = 'odd';
-       foreach ($attrMap as $attr)
+       foreach (getAttrMap() as $attr)
        {
                echo "<tr class=row_${order}>";
                echo "<td class=tdleft>${attr['name']}</td>";
@@ -3407,11 +3398,10 @@ function renderAttributes ()
                else
                        foreach ($attr['application'] as $app)
                                if ($attr['type'] == 'dict')
-                                       echo "${app['objtype_name']} (values from '${app['chapter_name']}')<br>";
+                                       echo decodeObjectType ($app['objtype_id'], 'a') . " (values from '${app['chapter_name']}')<br>";
                                else
-                                       echo "${app['objtype_name']}<br>";
-               echo '</td>';
-               echo "</tr>\n";
+                                       echo decodeObjectType ($app['objtype_id'], 'a') . '<br>';
+               echo '</td></tr>';
                $order = $nextorder[$order];
        }
        echo "</table><br>\n";
@@ -3432,13 +3422,12 @@ function renderEditAttributesForm ()
                printImageHREF ('add', 'Create attribute', TRUE, 102);
                echo '</td></tr></form>';
        }
-       $attrMap = getAttrMap();
        startPortlet ('Optional attributes');
        echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
        echo '<tr><th>&nbsp;</th><th>Name</th><th>Type</th><th>&nbsp;</th></tr>';
        if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
                printNewItemTR();
-       foreach ($attrMap as $attr)
+       foreach (getAttrMap() as $attr)
        {
                printOpFormIntro ('upd', array ('attr_id' => $attr['id']));
                echo '<tr><td>';
@@ -3467,38 +3456,40 @@ function renderEditAttrMapForm ()
        function printNewItemTR ($attrMap)
        {
                printOpFormIntro ('add');
-               echo '<tr><td>';
-               printImageHREF ('add', '', TRUE);
-               echo "</td><td><select name=attr_id tabindex=100>";
+               echo '<tr><td colspan=2 class=tdleft>';
+               echo '<select name=attr_id tabindex=100>';
                $shortType['uint'] = 'U';
                $shortType['float'] = 'F';
                $shortType['string'] = 'S';
                $shortType['dict'] = 'D';
                foreach ($attrMap as $attr)
                        echo "<option value=${attr['id']}>[" . $shortType[$attr['type']] . "] ${attr['name']}</option>";
-               echo "</select></td>";
-               echo '<td>';
-               printSelect (getObjectTypeList(), 'objtype_id', NULL, 101);
-               echo '</td>';
-               echo '<td><select name=chapter_no tabindex=102>';
+               echo "</select></td><td class=tdleft>";
+               printImageHREF ('add', '', TRUE);
+               echo ' ';
+               printNiftySelect (cookOptgroups (readChapter (CHAP_OBJTYPE, 'o')), 'objtype_id', NULL, 101);
+               echo ' <select name=chapter_no tabindex=102>';
                foreach (getChapterList() as $chapter)
                        if ($chapter['sticky'] != 'yes')
                                echo "<option value='${chapter['id']}'>${chapter['name']}</option>";
-               echo '</select></td><td>';
-               printImageHREF ('add', '', TRUE, 103);
-               echo '</td></tr>';
-               echo '</form>';
+               echo '</select></td></tr></form>';
        }
+       global $attrtypes, $nextorder;
+       $order = 'odd';
        $attrMap = getAttrMap();
        startPortlet ('Attribute map');
-       echo "<table cellspacing=0 cellpadding=5 align=center class=widetable>\n";
-       echo '<tr><th>&nbsp;</th><th>Attribute name</th><th>Object type</th><th>Dictionary chapter</th><th>&nbsp;</th></tr>';
+       echo "<table class=cooltable border=0 cellpadding=5 cellspacing=0 align=center>";
+       echo '<tr><th class=tdleft>Attribute name</th><th class=tdleft>Attribute type</th><th class=tdleft>Applies to</th></tr>';
        if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
                printNewItemTR ($attrMap);
        foreach ($attrMap as $attr)
+       {
+               if (!count ($attr['application']))
+                       continue;
+               echo "<tr class=row_${order}><td class=tdleft>${attr['name']}</td>";
+               echo "<td class=tdleft>" . $attrtypes[$attr['type']] . "</td><td colspan=2 class=tdleft>";
                foreach ($attr['application'] as $app)
                {
-                       echo '<tr><td>';
                        if ($app['refcnt'])
                                printImageHREF ('nodelete', $app['refcnt'] . ' value(s) stored for objects');
                        else
@@ -3507,15 +3498,15 @@ function renderEditAttrMapForm ()
                                printImageHREF ('delete', 'Remove mapping');
                                echo "</a>";
                        }
-                       echo "</td><td>${attr['name']}</td>";
-                       echo "<td>${app['objtype_name']}</td>";
-                       echo "<td>";
+                       echo ' ';
                        if ($attr['type'] == 'dict')
-                               echo "${app['chapter_name']}";
+                               echo decodeObjectType ($app['objtype_id'], 'o') . " (values from '${app['chapter_name']}')<br>";
                        else
-                               echo '&nbsp;';
-                       echo "</td></tr>\n";
+                               echo decodeObjectType ($app['objtype_id'], 'o') . '<br>';
                }
+               echo "</td></tr>";
+               $order = $nextorder[$order];
+       }
        if (getConfigVar ('ADDNEW_AT_TOP') != 'yes')
                printNewItemTR ($attrMap);
        echo "</table>\n";
@@ -4586,7 +4577,7 @@ function renderLivePTR ($id)
 function renderAutoPortsForm ($object_id)
 {
        $info = spotEntity ('object', $object_id);
-       $ptlist = readChapter ('PortType');
+       $ptlist = readChapter (CHAP_PORTTYPE, 'a');
        echo "<table class='widetable' border=0 cellspacing=0 cellpadding=5 align='center'>\n";
        echo "<caption>The following ports can be quickly added:</caption>";
        echo "<tr><th>type</th><th>name</th></tr>";
index 7f13eda20672412a07092af06eda039fd5989292..06b951a109eaad7ff5ba46aab505289f406ca331 100644 (file)
@@ -502,7 +502,8 @@ $msgcode['savePortMap']['ERR'] = 108;
 // and modifies database accordingly.
 function savePortMap ()
 {
-       $ptlist = getPortTypes();
+       // values' format doesn't matter, only keys are used
+       $ptlist = readChapter (CHAP_PORTTYPE);
        $oldCompat = getPortCompat();
        $newCompat = array();
        foreach (array_keys ($ptlist) as $leftKey)