Fork me on GitHub

Categories - filtering on multiple categories  Bottom

Go to page 1 - 2 [+1]:

  • Trying my first steps on the Categories journey I've created several module categories and properties. I get selectors to show them in my view template. That all works fine. Now I want to filter on a combination of selections in multiple categories. In News I find this:

    Code

    if ($modvars['enablecategorization']) {
            if (!($class = Loader::loadClass('CategoryUtil')) || !($class = Loader::loadClass('CategoryRegistryUtil'))) {
                pn_exit (pnML('_UNABLETOLOADCLASS', array('s' => 'CategoryUtil | CategoryRegistryUtil')));
            }
            // get the categories registered for the News stories
            $catregistry = CategoryRegistryUtil::getRegisteredModuleCategories('News', 'stories');
            $properties = array_keys($catregistry);
            $lang = pnUserGetLang();

            // validate the property
            // and build the category filter - mateo
            if (!empty($prop) && in_array($prop, $properties) && !empty($cat)) {
                if (!is_numeric($cat)) {
                    $rootCat = CategoryUtil::getCategoryByID($catregistry[$prop]);
                    $cat = CategoryUtil::getCategoryByPath($rootCat['path'].'/'.$cat);
                } else {
                    $cat = CategoryUtil::getCategoryByID($cat);
                }
                $catname = isset($cat['display_name'][$lang]) ? $cat['display_name'][$lang] : $cat['name'];

                if (!empty($cat) && isset($cat['path'])) {
                    // include all it's subcategories and build the filter
                    $categories = CategoryUtil::getCategoriesByPath($cat['path'], '', 'path');
                    $catstofilter = array();
                    foreach ($categories as $category) {
                        $catstofilter[] = $category['id'];
                    }
                    $catFilter = array($prop => $catstofilter);
                } else {
                    LogUtil::registerError(_NOTAVALIDCATEGORY);
                }
            }
        }


    This uses getRegisteredModuleCategories, which takes a specific registry entry. I have multiple registry entries. Now how would I go about creating a filter that combines multiple registry entries?
  • If I remember correctly you can do something like

    Code

    $catFilter = array(
        array($propOne => $catstofilterArrayOne),
        array($propTwo => $catstofilterArrayTwo),
        array($propThree => $catstofilterArrayThree)
    );


    instead of

    Code

    $catFilter = array($prop => $catstofilter);


    --
    Guite | ModuleStudio
  • That would be great! I'll try it out.
    Thanks.
  • Works like a dream! Thanks again.
  • icon_smile Now i guess that you built a cool web with many filters!
    and i want to see it! icon_razz

    Greetings Bert!

    --
    - Mateo T. -
    Mis principios... son mis fines
  • Hi Mateo,

    I'm afraid I have to disappoint you a bit there icon_wink . What I'm trying to do is not that shocking. For a Fairtrade organisation I'm adjusting the Addressbook module with several categories and add a mailing facility. Categories being stakeholder type (media, donor, ...), contact type (individual / organisation), receive newsletter (yes / no). The filtering on a combination of these criteria in the view function works great.

    What I'm battling with now is to store the categories selections in address create and update functions. Addressbook doesn't use pnForms for the templates involved. Thus I can't use the pnformcategoryselector plugin. In stead I use selector_category plugin. I presume what I need to do is override the PNObject updatePostProcess method and store the categories from there. But how icon_confused

    Using Pagesetter with relations and pgForm I could have created a similar solution much faster. I would very much like to finally learn how to work with categories though! The essential advantage of using categories for me is to be able to categorise information across modules. But I feel I've got loads left to learn icon_lol .
  • Stick with Pagesetter, for the love of all that is holy!

    ;)
  • dits

    What I'm battling with now is to store the categories selections in address create and update functions. Addressbook doesn't use pnForms for the templates involved. Thus I can't use the pnformcategoryselector plugin. In stead I use selector_category plugin. I presume what I need to do is override the PNObject updatePostProcess method and store the categories from there. But how icon_confused


    After some more digging I found out the category selections are being stored just fine. Turns out something is wrong with the filter after all icon_rolleyes . Will post further results here.

    P.S. I'm an atheist, to me nothing is holy icon_lol . Pagesetter does come close though!
  • Got it working icon_biggrin . One thing left: defining the filter array like this:

    Code

    $catFilter = array(
        array($propOne => $catstofilterArrayOne),
        array($propTwo => $catstofilterArrayTwo),
        array($propThree => $catstofilterArrayThree)
    );


    seems to be ORing the conditions. Is there a way to rather AND them?
  • The function _generateCategoryFilter in includes/DBUtil.class.php does this:

    Code

    $where = "cmo_table='" . DataUtil::formatForStore($tablename) . "' AND (" . implode(' OR ', $where) . ')';

    Changing it to this:

    Code

    $where = "cmo_table='" . DataUtil::formatForStore($tablename) . "' AND (" . implode(' AND ', $where) . ')';

    does what I would need it to do and what I would expect it to do.

    I expect a search to be AND by default. I expect selecting multiple categories to AND as well. Is this logical? Should I submit a ticket?

    P.S. SORRY SPOKE TO EARLY. The change above is not doing what I expected. Investigating ...



    edited by: dits, Oct 11, 2009 - 03:44 PM
  • In my experience the multi cat select is indeed or-ing the categories. In the news storiesext block you can select multiple categories, but (AFAIK icon_wink have to look to be sure again) it is an cat1 or cat2. Etc.
    The selector_category is being used there and that gives the or logic

    FYI Code in storiesext:

    Code

    <!--[foreach from=$catregistry key='prop' item='cat']-->
            <!--[array_field_isset assign='selectedValue' array=$category field=$prop returnValue=1]-->
            <li>
              <!--[selector_category category=$cat name="category[$prop]" multipleSize=5 selectedValue=$selectedValue]-->
              <input type="button" value="<!--[pnml name='_ALL']-->" onclick="news_storiesextblock_selectAllOptions(this.form.category_<!--[$prop]-->___, true);">
              <input type="button" value="<!--[pnml name='_STORIES_SELECTNONE']-->" onclick="news_storiesextblock_selectAllOptions(this.form.category_<!--[$prop]-->___, false);">
            </li>
        <!--[/foreach]-->


    --
    campertoday.nl, Module development, Dutch Zikula Community
  • Thanks for the feedback Erik.

    I think in your case there are multiple multiselects where you can choose more than one property value per category (is that correct). OR-ing the multiple selections for one property is logical. That seems to be achieved here:

    Code

    $wherecat = '(' . implode(' OR ', $wherecat) . ')';


    But, having several selects (be it single selects, or multiple selects), I would expect these to be AND-ded. Do you agree?

    I've made a preliminary patch for the _generateCategoryFilter in includes/DBUtil.class.php that does what I expect it to do. I'll post it just now.
  • I've patch the _generateCategoryFilter in includes/DBUtil.class.php as follows:

    Code

    // build the where clause
            $where = array();
            $count = 1;
            foreach ($categoryFilter as $property => $category) {
                // this allows to have an array of categories IDs
                if (is_array($category)) {
                    $wherecat = array();
                    foreach ($category as $cat) {
                        $wherecat[] = "mapobj".$count.".cmo_category_id='".DataUtil::formatForStore($cat)."'";
                    }
                    $wherecat = '('.implode(' OR ', $wherecat).')';

                // if there's only one category ID
                } else {
                    $wherecat = "mapobj".$count.".cmo_category_id='".DataUtil::formatForStore($category)."'";
                }
                $where[] = "cmo_obj_id = (SELECT mapobj".$count.".cmo_obj_id FROM pn_categories_mapobj mapobj".$count." WHERE mapobj".$count.".cmo_reg_id = '".DataUtil::formatForStore($propids[$property])."' AND ".$wherecat.")";
                $count++;
            }
            $where  = "cmo_table='".DataUtil::formatForStore($tablename)."' AND (".implode(' AND ', $where).")";

    It's not too elegant, but it works and I'm not yet familiar enough with the DBUtil class.

    The main question remains: to AND OR not to AND?
  • True, there are multiple multiselects if you have multiple cat registries set in place. Ah ok, You mean for several props that the cat in that prop is AND selected with the cat in the other prop.
    I can thinks of cases where you would want one or the other. I don't use multi props in my track&field site. I have only done testing in my testsite with multiple cat registries. So I'm not sure what you would want ot choose. It might be that you would want a choice to choose OR-ing or AND-ing.

    --
    campertoday.nl, Module development, Dutch Zikula Community
  • espaan

    You mean for several props that the cat in that prop is AND selected with the cat in the other prop.

    Exactly.

    espaan

    So I'm not sure what you would want ot choose. It might be that you would want a choice to choose OR-ing or AND-ing.

    I would expect the default being AND-ing, but I might be biased because of the specific implementation I'm working on icon_wink .

Go to page 1 - 2 [+1]:

This list is based on users active over the last 60 minutes.