Changeset 11915

Show
Ignore:
Timestamp:
08/30/07 20:24:14 (1 year ago)
Author:
rambo
Message:

refs #102

querybuilder: minor fix in to-be-deprecated execute_notwindowed adjusted
comments

collector: made _unchecked methdos work like QB counterparts (ie
limit/offset is applied before execution and ACLs checked later, see
method documentation) adjusted comments, etc

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/midcom/midcom.core/midcom/core/collector.php

    r11911 r11915  
    101101     * the query. 
    102102     * 
     103     * NOTE: Checks not implemented yet 
     104     * 
    103105     * Be aware, that this setting will currently not use the QB to filter the objects accordingly, 
    104106     * since there is no way yet to filter against parameters. This will mean some performance 
    105107     * impact. 
    106108     * 
    107      * While on-site, this is enabled by default, in AIS it is disabled by default. 
    108      */ 
    109     var $hide_invisible = false; 
     109     */ 
     110    var $hide_invisible = true; 
     111 
     112    /** 
     113     * Keep track if $this->execute has been called 
     114     */ 
     115    var $_executed = false; 
    110116 
    111117    /** 
     
    158164        // MidCOM's collector always uses the GUID as the key for ACL purposes 
    159165        $this->_mc->set_key_property('guid'); 
    160  
    161         if (! array_key_exists("view_contentmgr", $GLOBALS)) 
    162         { 
    163             $this->hide_invisible = true; 
    164              
    165             if ($GLOBALS['midcom_config']['i18n_multilang_strict'] 
    166                 && $_MIDCOM->i18n->get_midgard_language() != 0) 
    167             { 
    168                 // FIXME: Re-enable this when it actually works 
    169                 // $this->_mc->set_lang($_MIDCOM->i18n->get_midgard_language()); 
    170             } 
    171         } 
    172     } 
    173  
     166        if (   $GLOBALS['midcom_config']['i18n_multilang_strict'] 
     167            /* Why is this check here (check querybuilder.php for same functionality without this check) ? 
     168            && $_MIDCOM->i18n->get_midgard_language() != 0 
     169            */) 
     170        { 
     171            // FIXME: Re-enable this when it actually works 
     172            $this->_mc->set_lang($_MIDCOM->i18n->get_midgard_language()); 
     173        } 
     174    } 
    174175 
    175176    /** 
     
    181182        call_user_func_array(array($this->_real_class, '_on_prepare_new_collector'), array(&$this)); 
    182183    } 
    183  
    184184 
    185185    /** 
     
    192192     * 1. bool _on_prepare_exec_collector(&$this) is called before the actual query execution. Return false to 
    193193     *    abort the operation. 
    194      * 2. The query is executed. 
    195      * 3. void _on_process_query_result(&$result) is called after the successful execution of the query. You 
    196      *    may remove any unwanted entries from the resultset at this point. 
    197      * 
    198      * If the execution of the query fails for some reason all available error information is logged 
    199      * and a MIDCOM_ERRCRIT level error is triggered, halting execution. 
    200      * 
    201      * @param midgard_collector $mc An instance of the Query builder obtained by the new_collector 
    202      *     function of this class. 
    203      * @return Array The result of the collector or null on any error. Note, that empty resultsets 
    204      *     will return an empty array. 
    205      * @todo Implement proper count / Limit support. 
     194     * 
     195     * @return boolean indicating success/failure 
     196     * @see _real_execute() 
    206197     */ 
    207198    function execute() 
     
    212203            debug_add('The _on_prepare_exec_collector callback returned false, so we abort now.'); 
    213204            debug_pop(); 
    214             return null; 
    215         } 
    216  
    217         // Workaround until the QB does return empty arrays: All errors are empty resultsets and errors are ignored. 
    218         $result = $this->_mc->execute(); 
    219         if (!$result) 
    220         { 
    221             // Workaround mode for now 
    222             if (mgd_errno() != MGD_ERR_OK) 
    223             { 
    224                 debug_push_class(__CLASS__, __FUNCTION__); 
    225                 debug_print_r('Result was:', $result); 
    226                 debug_add('The collector failed to execute, aborting.', MIDCOM_LOG_ERROR); 
    227                 debug_add('Last Midgard error was: ' . mgd_errstr(), MIDCOM_LOG_ERROR); 
    228                 if (isset($php_errormsg)) 
    229                 { 
    230                     debug_add("Error message was: {$php_errormsg}", MIDCOM_LOG_ERROR); 
    231                 } 
    232                 debug_pop(); 
    233                 $_MIDCOM->generate_error(MIDCOM_ERRCRIT, 
    234                     'The collector failed to execute, see the log file for more information.'); 
    235                 // This will exit. 
    236             } 
    237         } 
    238          
    239         return $result; 
     205            return false; 
     206        } 
     207        $this->_executed = true; 
     208        return true; 
     209    } 
     210 
     211    /** 
     212     * Executes the MC 
     213     * 
     214     * @return void 
     215     * @see midgard_collector::execute() 
     216     */ 
     217    function _real_execute() 
     218    { 
     219        return $this->_mc->execute(); 
    240220    } 
    241221     
     222    /** 
     223     * Resets some internal variables for re-execute 
     224     */ 
     225    function _reset() 
     226    { 
     227        $this->_executed = false; 
     228        $this->count = -1; 
     229        $this->denied = 0; 
     230    } 
     231 
     232    /** 
     233     * Runs a query where <i>limit and offset is taken into account prior to 
     234     * execution in the core.</i> 
     235     * 
     236     * This is useful in cases where you can safely assume read privileges on all 
     237     * objects, and where you would otherwise have to deal with huge resultsets. 
     238     * 
     239     * Be aware that this might lead to empty resultsets "in the middle" of the 
     240     * actual full resultset when read privileges are missing. 
     241     * 
     242     * @see list_keys() 
     243     */ 
    242244    function list_keys_unchecked() 
    243245    { 
    244         return $this->_mc->list_keys(); 
    245     } 
    246      
     246        $this->_reset(); 
     247        // Add the limit / offsets 
     248        if ($this->_limit) 
     249        { 
     250            $this->_mc->set_limit($this->_limit); 
     251        } 
     252        if ($this->_offset) 
     253        { 
     254            $this->_mc->set_offset($this->_offset); 
     255        } 
     256 
     257        $newresult = $this->_list_keys_and_check_privileges(); 
     258 
     259        if (!is_array($newresult)) 
     260        { 
     261            return $newresult; 
     262        } 
     263 
     264        call_user_func_array(array($this->_real_class, '_on_process_collector_result'), array(&$newresult)); 
     265 
     266        $this->count = count($newresult); 
     267 
     268        debug_pop(); 
     269        return $newresult; 
     270    } 
     271 
     272    function _list_keys_and_check_privileges() 
     273    { 
     274        $this->_real_execute(); 
     275        $result = $this->_mc->list_keys(); 
     276        if (!is_array($result)) 
     277        { 
     278            return $result; 
     279        } 
     280        $newresult = array(); 
     281        $classname = $this->_real_class; 
     282        foreach ($result as $object_guid => $empty_copy) 
     283        { 
     284            if (!$_MIDCOM->auth->can_do_byguid('midgard:read', $object_guid, $classname)) 
     285            { 
     286                debug_add("Failed to load result, read privilege on {$object_guid} not granted for the current user.", MIDCOM_LOG_INFO); 
     287                $this->denied++; 
     288                continue; 
     289            } 
     290 
     291            // Check visibility 
     292            if ($this->hide_invisible) 
     293            { 
     294                // TODO: Implement 
     295            } 
     296 
     297            $newresult[$object_guid] = array(); 
     298        } 
     299        return $newresult; 
     300    } 
     301 
     302    /** 
     303     * implements midgard_collector::list_keys with ACL and visibility checking 
     304     * 
     305     * @todo implement visibility checking 
     306     */ 
    247307    function list_keys() 
    248308    { 
    249         $result = $this->_mc->list_keys(); 
     309        /** 
     310         * PONDER: Should we implement the moving window limit/offset handling here as well ? 
     311         * probably it's not worth the effort since we're not actually instantiating objects  
     312         * so many of the inefficencies related to that are avoided. 
     313         * @see midcom_core_querybuilder::execute_windowed 
     314         */ 
     315        $this->_reset(); 
     316        $result = $this->_list_keys_and_check_privileges(); 
     317        if (!is_array($result)) 
     318        { 
     319            return $result; 
     320        } 
    250321        $newresult = array(); 
    251                  
    252         if (!$result) 
    253         { 
    254             return $newresult; 
    255         } 
    256  
    257         // Workaround until the QB returns the correct type, refetch everything 
    258         $classname = $this->_real_class; 
     322 
    259323        $limit = $this->_limit; 
    260324        $offset = $this->_offset; 
    261         $skipped_objects = 0; 
    262         $this->denied = 0; 
     325        $classname = $this->_real_class; 
    263326        foreach ($result as $object_guid => $empty_copy) 
    264327        { 
     328            // We have hit our limit 
    265329            if (   $this->_limit > 0 
    266330                && $limit == 0) 
    267331            { 
    268                 $skipped_objects++; 
    269                 continue; 
     332                break; 
    270333            } 
    271334 
     
    274337                debug_add("Failed to load result, read privilege on {$object_guid} not granted for the current user.", MIDCOM_LOG_INFO); 
    275338                $this->denied++; 
    276                 $skipped_objects++; 
    277339                continue; 
    278340            } 
     
    292354            } 
    293355 
    294             $newresult[$object_guid] = array()
     356            $newresult[$object_guid] = $empty_copy
    295357 
    296358            if ($this->_limit > 0) 
     
    302364        call_user_func_array(array($this->_real_class, '_on_process_collector_result'), array(&$newresult)); 
    303365 
    304         /* This must some QB copy-paste leftover 
    305         // correct record count by the number of limit-skipped objects. 
    306         $this->count = count($newresult) + $skipped_objects; 
    307         */ 
    308366        $this->count = count($newresult); 
    309367 
    310         debug_pop(); 
    311368        return $newresult; 
    312369    } 
     
    350407    function add_constraint($field, $operator, $value) 
    351408    { 
     409        $this->_reset(); 
    352410        // Add check against null values, Core QB is too stupid to get this right. 
    353411        if ($value === null) 
     
    381439    function add_order($field, $ordering = null) 
    382440    { 
     441        /** 
     442         * NOTE: So see also querybuilder.php when making changes here 
     443         */ 
    383444        if (empty($field)) 
    384445        { 
     
    396457        if ($ordering === null) 
    397458        { 
    398             $result = $this->_mc->add_order($field); 
     459            if (substr($field, 0, 8) == 'reverse ') 
     460            { 
     461                $result = $this->_mc->add_order(substr($field, 8), 'DESC'); 
     462            } 
     463            else 
     464            { 
     465                $result = $this->_mc->add_order($field); 
     466            } 
    399467        } 
    400468        else 
     
    446514     * @param int $count The maximum number of records in the resultset. 
    447515     */ 
    448     function set_limit($count) 
    449     { 
    450         $this->_limit = $count; 
     516    function set_limit($limit) 
     517    { 
     518        $this->_reset(); 
     519        $this->_limit = $limit; 
    451520    } 
    452521 
     
    463532    function set_offset($offset) 
    464533    { 
     534        $this->_reset(); 
    465535        $this->_offset = $offset; 
    466536    } 
     
    475545    function set_lang($language) 
    476546    { 
     547        $this->_reset(); 
    477548        $this->_mc->set_lang($language); 
    478549    } 
     
    495566     * Returns the number of elements matching the current query. 
    496567     * 
    497      * <i>Developer's note:</i> According to the Midgard core documentation, the count method 
    498      * does <b>not</b> execute the query using some COUNT() SQL statement. It merely returns 
    499      * the number of records found and is, thus, mostly useless as you can just count($result) 
    500      * on the PHP level anyway. 
    501      * 
    502      * To match the original inteded behavoir, the class will automatically execute the given 
    503      * query if it has not yet been executed, thus breaking full API compatibility to the Midgard 
    504      * core deliberatly on this point. 
    505      * 
    506      * Therefore, it is currently <i>strongly discouraged</i> to assume midgard_collector::count 
    507      * to be useful as-is. See http://midgard.tigris.org/issues/show_bug.cgi?id=56 for details. 
     568     * Due to ACL checking we must first execute the full query 
    508569     * 
    509570     * @return int The number of records found by the last query. 
     
    513574        if ($this->count == -1) 
    514575        { 
    515             $this->execute(); 
    516             // TODO: ACL check 
     576            if (!$this->_executed) 
     577            { 
     578                $this->execute(); 
     579            } 
     580            $this->list_keys(); 
    517581        } 
    518582        return $this->count; 
     
    528592     * mind might nevertheless be able to take advantage of it. 
    529593     * 
    530      * @return int The number of records matching the last query without taking access control into account. 
     594     * @return int The number of records matching the constraints without taking access control or visibility into account. 
    531595     */ 
    532596    function count_unchecked() 
    533597    { 
     598        $this->_reset(); 
     599        if ($this->_limit) 
     600        { 
     601            $this->_mc->set_limit($this->_limit); 
     602        } 
     603        if ($this->_offset) 
     604        { 
     605            $this->_mc->set_offset($this->_offset); 
     606        } 
    534607        return $this->_mc->count(); 
    535608    } 
    536609} 
    537610 
    538  
    539611?> 
  • trunk/midcom/midcom.core/midcom/core/querybuilder.php

    r11906 r11915  
    591591        $limit = $this->_limit; 
    592592        $offset = $this->_offset; 
    593         $skipped_objects = 0; 
    594593        $this->denied = 0; 
    595594 
     
    599598                && $limit == 0) 
    600599            { 
    601                 $skipped_objects++; 
    602                 continue; 
     600                break; 
    603601            } 
    604602 
     
    627625 
    628626    /** 
    629      * Temporary helper until execute can be optimized with rerunnable QBs, 
    630      * runs a query where <i>limit and offset is taken into account prior to 
     627     * Runs a query where <i>limit and offset is taken into account prior to 
    631628     * execution in the core.</i> 
    632629     * 
     
    733730    function add_order($field, $ordering = null) 
    734731    { 
     732        /** 
     733         * NOTE: So see also collector.php when making changes here 
     734         */ 
    735735        if (! $field) 
    736736        { 
     
    854854     * Returns the number of elements matching the current query. 
    855855     * 
    856      * Due to ACL checking we must first execute the full query to get 
     856     * Due to ACL checking we must first execute the full query 
    857857     * 
    858858     * @return int The number of records found by the last query. 
     
    891891    } 
    892892} 
     893 
    893894?>