Changeset 174 for trunk/lib/ACL.inc.php


Ignore:
Timestamp:
Jun 18, 2006 8:50:35 AM (18 years ago)
Author:
scdev
Message:

Q - added move method to ACL class, added polish.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/lib/ACL.inc.php

    r173 r174  
    66* Uses Modified Preorder Tree Traversal to maintain a tree-structure.
    77* See: http://www.sitepoint.com/print/hierarchical-data-database
    8 * Includes a command-line tool for managing rights.
     8* Includes a command-line tool for managing rights (codebase/bin/acl.cli.php).
    99*
    1010* Code by Strangecode :: www.strangecode.com :: This document contains copyrighted information.
     
    2929
    3030    /**
    31      * Prefs constructor.
     31     * Constructor.
    3232     */
    3333    function ACL()
     
    102102
    103103    /**
    104      * Setup the database table for this class.
     104     * Setup the database tables for this class.
    105105     *
    106106     * @access  public
     
    192192
    193193    /*
    194     *
     194    * Add a node to one of the aro/aco/axo tables.
    195195    *
    196196    * @access   public
    197     * @param   
    198     * @return   
     197    * @param    string $name A unique identifier for the new node.
     198    * @param    string $parent The name of the parent under-which to attach the new node.
     199    * @param    string $type The tree to add to, one of: aro, aco, axo.
     200    * @return   bool | int False on error, or the last_insert_id primary key of the new node.
    199201    * @author   Quinn Comendant <quinn@strangecode.com>
    200202    * @version  1.0
     
    244246        // Select the rgt of $parent.
    245247        $qid = $db->query("SELECT rgt FROM $tbl WHERE name = '" . $db->escapeString($parent) . "'");
    246         if (!list($rgt) = mysql_fetch_row($qid)) {
     248        if (!list($parent_rgt) = mysql_fetch_row($qid)) {
    247249            $app->logMsg(sprintf('Cannot add %s node to nonexistant parent: %s', $type, $parent), LOG_WARNING, __FILE__, __LINE__);
    248250            return false;
    249251        }
     252
    250253        // Update transversal numbers for all nodes to the rgt of $parent.
    251         $db->query("UPDATE $tbl SET lft = lft + 2 WHERE lft >= $rgt");
    252         $db->query("UPDATE $tbl SET rgt = rgt + 2 WHERE rgt >= $rgt");
     254        $db->query("UPDATE $tbl SET lft = lft + 2 WHERE lft >= $parent_rgt");
     255        $db->query("UPDATE $tbl SET rgt = rgt + 2 WHERE rgt >= $parent_rgt");
    253256       
    254257        // Insert new node just below parent. Lft is parent's old rgt.
    255258        $db->query("
    256259            INSERT INTO $tbl (name, lft, rgt, added_datetime)
    257             VALUES ('" . $db->escapeString($name) . "', $rgt, $rgt + 1, NOW())
     260            VALUES ('" . $db->escapeString($name) . "', $parent_rgt, $parent_rgt + 1, NOW())
    258261        ");
    259262
     
    263266
    264267    // Alias functions for the different object types.
    265     function addARO($name, $parent=null)
     268    function addRequestObject($name, $parent=null)
    266269    {
    267270        return $this->add($name, $parent, 'aro');
    268271    }
    269     function addACO($name, $parent=null)
     272    function addControlObject($name, $parent=null)
    270273    {
    271274        return $this->add($name, $parent, 'aco');
    272275    }
    273     function addAXO($name, $parent=null)
     276    function addXtraObject($name, $parent=null)
    274277    {
    275278        return $this->add($name, $parent, 'axo');
     
    277280
    278281    /*
    279     *
     282    * Remove a node from one of the aro/aco/axo tables.
    280283    *
    281284    * @access   public
    282     * @param   
    283     * @return   
     285    * @param    string $name The identifier for the node to remove.
     286    * @param    string $type The tree to modify, one of: aro, aco, axo.
     287    * @return   bool | int False on error, or true on success.
    284288    * @author   Quinn Comendant <quinn@strangecode.com>
    285289    * @version  1.0
     
    296300        case 'aro' :
    297301            $tbl = 'aro_tbl';
     302            $primary_key = 'aro_id';
    298303            break;
    299304        case 'aco' :
    300305            $tbl = 'aco_tbl';
     306            $primary_key = 'aco_id';
    301307            break;
    302308        case 'axo' :
    303309            $tbl = 'axo_tbl';
     310            $primary_key = 'axo_id';
    304311            break;
    305312        default :
     
    315322        }
    316323       
    317         // Select the lft of $name
     324        // Select the lft and rgt of $name to use for selecting children and reordering transversals.
    318325        $qid = $db->query("SELECT lft, rgt FROM $tbl WHERE name = '" . $db->escapeString($name) . "'");
    319326        if (!list($lft, $rgt) = mysql_fetch_row($qid)) {
     
    322329        }
    323330       
    324         // Remove node and all children of node.
    325         $db->query("DELETE FROM $tbl WHERE lft BETWEEN $lft AND $rgt");
     331        // Remove node and all children of node, as well as acl_tbl links.
     332        $db->query("
     333            DELETE $tbl, acl_tbl
     334            FROM $tbl
     335            LEFT JOIN acl_tbl ON ($tbl.$primary_key = acl_tbl.$primary_key)
     336            WHERE $tbl.lft BETWEEN $lft AND $rgt
     337        ");
    326338        $num_deleted_nodes = mysql_affected_rows($db->getDBH());
    327339
     
    335347   
    336348    // Alias functions for the different object types.
    337     function removeUser($name, $parent=null)
    338     {
    339         return $this->remove($name, $parent, 'aro');
    340     }
    341     function removeAction($name, $parent=null)
    342     {
    343         return $this->remove($name, $parent, 'aco');
    344     }
    345     function removeObject($name, $parent=null)
    346     {
    347         return $this->remove($name, $parent, 'axo');
     349    function removeRequestObject($name)
     350    {
     351        return $this->remove($name, 'aro');
     352    }
     353    function removeControlObject($name)
     354    {
     355        return $this->remove($name, 'aco');
     356    }
     357    function removeXtraObject($name)
     358    {
     359        return $this->remove($name, 'axo');
     360    }
     361
     362    /*
     363    * Move a node to a new parent in one of the aro/aco/axo tables.
     364    *
     365    * @access   public
     366    * @param    string $name The identifier for the node to remove.
     367    * @param    string $new_parent The name of the parent under-which to attach the new node.
     368    * @param    string $type The tree to modify, one of: aro, aco, axo.
     369    * @return   bool | int False on error, or the last_insert_id primary key of the new node.
     370    * @author   Quinn Comendant <quinn@strangecode.com>
     371    * @version  1.0
     372    * @since    14 Jun 2006 22:39:29
     373    */
     374    function move($name, $new_parent, $type)
     375    {
     376        $app =& App::getInstance();
     377        $db =& DB::getInstance();
     378       
     379        $this->initDB();
     380
     381        switch ($type) {
     382        case 'aro' :
     383            $tbl = 'aro_tbl';
     384            $primary_key = 'aro_id';
     385            break;
     386        case 'aco' :
     387            $tbl = 'aco_tbl';
     388            $primary_key = 'aco_id';
     389            break;
     390        case 'axo' :
     391            $tbl = 'axo_tbl';
     392            $primary_key = 'axo_id';
     393            break;
     394        default :
     395            $app->logMsg(sprintf('Invalid access object type: %s', $type), LOG_ERR, __FILE__, __LINE__);
     396            return false;
     397            break;
     398        }
     399       
     400        // If $parent is null, use root object.
     401        if (is_null($parent)) {
     402            $parent = 'root';
     403        }
     404       
     405        // Ensure node and parent name aren't empty.
     406        if ('' == trim($name) || '' == trim($parent)) {
     407            $app->logMsg(sprintf('Cannot add node, parent (%s) or name (%s) missing.', $name, $parent), LOG_WARNING, __FILE__, __LINE__);
     408            return false;
     409        }
     410       
     411        // Select the lft and rgt of $name to use for selecting children and reordering transversals.
     412        $qid = $db->query("SELECT lft, rgt FROM $tbl WHERE name = '" . $db->escapeString($name) . "'");
     413        if (!list($lft, $rgt) = mysql_fetch_row($qid)) {
     414            $app->logMsg(sprintf('Cannot delete nonexistant %s name: %s', $type, $name), LOG_NOTICE, __FILE__, __LINE__);
     415            return false;
     416        }
     417       
     418        // Total number of transversal values (that is, the count of self plus all children times two).
     419        $total_transversal_value = ($rgt - $lft + 1);
     420
     421        // Select the rgt of the new parent.
     422        $qid = $db->query("SELECT rgt FROM $tbl WHERE name = '" . $db->escapeString($new_parent) . "'");
     423        if (!list($new_parent_rgt) = mysql_fetch_row($qid)) {
     424            $app->logMsg(sprintf('Cannot move %s node to nonexistant parent: %s', $type, $new_parent), LOG_WARNING, __FILE__, __LINE__);
     425            return false;
     426        }
     427       
     428        // Ensure the new parent is not a child of the node being moved.
     429        if ($new_parent_rgt <= $rgt && $new_parent_rgt >= $lft) {
     430            $app->logMsg(sprintf('Cannot move %s node %s to parent %s because it is a child of itself.', $type, $name, $new_parent), LOG_WARNING, __FILE__, __LINE__);
     431            return false;
     432        }
     433       
     434        // Collect unique ids of all nodes being moved. The transversal numbers will become duplicated so these will be needed to identify these.
     435        $qid = $db->query("
     436            SELECT $primary_key
     437            FROM $tbl
     438            WHERE lft BETWEEN $lft AND $rgt
     439            AND rgt BETWEEN $lft AND $rgt
     440        ");
     441        $ids = array();
     442        while (list($id) = mysql_fetch_row($qid)) {
     443            $ids[] = $id;
     444        }
     445
     446        // Update transversal numbers for all nodes to the rgt of the node being moved, taking in to account the absence of it's children.
     447        // This will temporarily "remove" the node from the tree, and its transversal values will be duplicated.
     448        $db->query("UPDATE $tbl SET lft = lft - $total_transversal_value WHERE lft > $rgt");
     449        $db->query("UPDATE $tbl SET rgt = rgt - $total_transversal_value WHERE rgt > $rgt");
     450        // Apply transformation to new parent rgt also.
     451        $new_parent_rgt = $new_parent_rgt > $rgt ? $new_parent_rgt - $total_transversal_value : $new_parent_rgt;
     452       
     453        // Update transversal values of moved node and children.
     454        $db->query("
     455            UPDATE $tbl SET
     456                lft = lft - ($lft - $new_parent_rgt),
     457                rgt = rgt - ($lft - $new_parent_rgt)
     458            WHERE $primary_key IN ('" . join("','", $ids) . "')
     459        ");
     460
     461        // Update transversal values of all nodes to the rgt of moved node.
     462        $db->query("UPDATE $tbl SET lft = lft + $total_transversal_value WHERE lft >= $new_parent_rgt AND $primary_key NOT IN ('" . join("','", $ids) . "')");
     463        $db->query("UPDATE $tbl SET rgt = rgt + $total_transversal_value WHERE rgt >= $new_parent_rgt AND $primary_key NOT IN ('" . join("','", $ids) . "')");
     464
     465        die;
     466        $app->logMsg(sprintf('Moved %s node %s to new parent %s.', $type, $name, $new_parent), LOG_DEBUG, __FILE__, __LINE__);
     467        return true;
     468    }
     469   
     470    // Alias functions for the different object types.
     471    function moveRequestObject($name, $new_parent=null)
     472    {
     473        return $this->move($name, $new_parent, 'aro');
     474    }
     475    function moveControlObject($name, $new_parent=null)
     476    {
     477        return $this->move($name, $new_parent, 'aco');
     478    }
     479    function moveXtraObject($name, $new_parent=null)
     480    {
     481        return $this->move($name, $new_parent, 'axo');
    348482    }
    349483   
    350484    /*
    351     *
     485    * Add an entry to the acl_tbl to allow (or deny) a truple with the specified
     486    * ARO -> ACO -> AXO entry.
    352487    *
    353488    * @access   public
    354     * @param   
    355     * @return   
     489    * @param    string $aro Identifier of an existing ARO object.
     490    * @param    string $aco Identifier of an existing ACO object (or null to use root).
     491    * @param    string $axo Identifier of an existing AXO object (or null to use root).
     492    * @return   bool False on error, true on success.
    356493    * @author   Quinn Comendant <quinn@strangecode.com>
    357494    * @version  1.0
     
    397534
    398535    /*
    399     *
     536    * Add an entry to the acl_tbl to deny a truple with the specified
     537    * ARO -> ACO -> AXO entry. This calls the ACL::grant function to create the entry
     538    * but uses 'deny' as the fourth argument.
    400539    *
    401540    * @access   public
    402     * @param   
    403     * @return   
     541    * @param    string $aro Identifier of an existing ARO object.
     542    * @param    string $aco Identifier of an existing ACO object (or null to use root).
     543    * @param    string $axo Identifier of an existing AXO object (or null to use root).
     544    * @return   bool False on error, true on success.
    404545    * @author   Quinn Comendant <quinn@strangecode.com>
    405546    * @version  1.0
     
    412553   
    413554    /*
    414     *
     555    * Calculates the most specific cascading privilege found for a requested
     556    * ARO -> ACO -> AXO entry. Returns FALSE if the entry is denied. By default,
     557    * all entries are denied, unless some point in the hierarchy is set ao "allow."
    415558    *
    416559    * @access   public
    417     * @param   
    418     * @return   
     560    * @param    string $aro Identifier of an existing ARO object.
     561    * @param    string $aco Identifier of an existing ACO object (or null to use root).
     562    * @param    string $axo Identifier of an existing AXO object (or null to use root).
     563    * @return   bool False if denied, true on allowed.
    419564    * @author   Quinn Comendant <quinn@strangecode.com>
    420565    * @version  1.0
Note: See TracChangeset for help on using the changeset viewer.