1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Two Criterias

Discussion in 'XenForo Development Discussions' started by Robust, Jan 24, 2016.

  1. Robust

    Robust Well-Known Member

    So I want to have two criterias:
    • Criteria to ACHIEVE something
    • Criteria to be ABLE to achieve something
    When I do this:

    Code:
            $viewParams = array(
                'task' => $task,
                'userCriteria' => XenForo_Helper_Criteria::prepareCriteriaForSelection($task['user_criteria']),
                'userCriteriaData' => XenForo_Helper_Criteria::getDataForUserCriteriaSelection(),
                'visibleCriteria' => XenForo_Helper_Criteria::prepareCriteriaForSelection($task['visible_criteria']),
                'visibleCriteriaData' => XenForo_Helper_Criteria::getDataForUserCriteriaSelection()
            );
    If I view the visibleCriteria tab (obviously you can't state what criteria param to use) they both sync, but the second one is a bit buggy (e.g. you can click usergroups when the checkbox isn't ticked).

    Is there no way to have two criterias on one "task"?
     
  2. Robust

    Robust Well-Known Member

    Is this possible?
     
  3. Robust

    Robust Well-Known Member

    Would manipulation of xen:map make this work?
     
  4. Robust

    Robust Well-Known Member

    xen:map doesn't seem to work because the criteria vars are still the same, so the second criteria bunch won't work. When they're processed through XenForo_Input, they're both user_criteria, but this time only the first one has the vars set, the second is just empty criteria.

    Is this even possible? How?

    Sorry for being so buggy, it's just I can't figure it out and it's kind of important.
     
  5. Lawrence

    Lawrence Well-Known Member

    I use my item criteria helper two ways, one to determine if a user's character can purchase a specific item, and another if a character can actually equip it.

    You need to send a different argument for each time you call your criteria method; one for the user and one to determine if it is going to be visible to the user or not. That is how my shop add-on works to determine if a user meets the criteria to purchase a specific item (ie: belongs to the proper usergroup), and then equip it (ie: has the required strength, or is a wizard, etc). What you want to achieve doesn't sound much different than how I am using my criteria helper.
     
    Robust likes this.
  6. Robust

    Robust Well-Known Member

    Late following this up. I didn't remember this ever being responded to.

    Sounds about the same though, what we were trying to do.

    Here's some code snippets:

    Code:
        <ul id="taskPanes">
            <li>
    /* other stuff */
            </li>
            <li>
                <xen:include template="helper_criteria_user">
                    <xen:map from="$achieveCriteria" to="$userCriteria" />
                    <xen:map from="$achieveCriteriaData" to="$userCriteriaData" />
                    <xen:set var="$criteriaHintHtml">{xen:phrase aupp_user_must_meet_all_criteria}</xen:set>
                </xen:include>
                <xen:include template="helper_criteria_user_date">
                    <xen:map from="$achieveCriteria" to="$userCriteria" />
                    <xen:map from="$achieveCriteriaData" to="$userCriteriaData" />
                    <xen:set var="$noDateFields">1</xen:set>
                </xen:include>
            </li>
            <li>
                <xen:include template="helper_criteria_user_field">
                    <xen:map from="$achieveCriteria" to="$userCriteria" />
                    <xen:map from="$achieveCriteriaData" to="$userCriteriaData" />
                </xen:include>
            </li>
            <li>
                <xen:include template="helper_criteria_user">
                    <xen:map from="$visibleCriteria" to="$userCriteria" />
                    <xen:map from="$visibleCriteriaData" to="$userCriteriaData" />
                    <xen:set var="$criteriaHintHtml">{xen:phrase aupp_user_must_meet_all_criteria}</xen:set>
                </xen:include>
                <xen:include template="helper_criteria_user_date">
                    <xen:map from="$visibleCriteria" to="$userCriteria" />
                    <xen:map from="$visibleCriteriaData" to="$userCriteriaData" />
                    <xen:set var="$noDateFields">1</xen:set>
                </xen:include>
            </li>
            <li>
                <xen:include template="helper_criteria_user_field">
                    <xen:map from="$visibleCriteria" to="$userCriteria" />
                    <xen:map from="$visibleCriteriaData" to="$userCriteriaData" />
                </xen:include>
            </li>
        </ul>
    However, when saving, 'user_criteria' is populated properly with the criteria options while 'visible_criteria' is an empty array.

    Code:
            $viewParams = array(
                'task' => $task,
                'achieveCriteria' => XenForo_Helper_Criteria::prepareCriteriaForSelection($task['user_criteria']),
                'achieveCriteriaData' => XenForo_Helper_Criteria::getDataForUserCriteriaSelection(),
                'visibleCriteria' => XenForo_Helper_Criteria::prepareCriteriaForSelection($task['visible_criteria']),
                'visibleCriteriaData' => XenForo_Helper_Criteria::getDataForUserCriteriaSelection()
            );
    I even have some redundant code there to be sure, but it doesn't work. The criteria to view (aka to be able to achieve) is always just an empty array.

    Probably because the variable name is hardcoded: name="user_criteria[is_guest][rule]"

    No way to change what it's bound to.
     
  7. Robust

    Robust Well-Known Member

    Anyone have any idea on this? XF staff?
     
  8. Lawrence

    Lawrence Well-Known Member

    The criteria I use is custom for the armory (shops) I have created, so I may not be that helpful as I never had the need to use/extend existing ones. I created mine the same way XF handles them:

    First step is to prepare each criteria for the preSave, if they exist.

    PHP:
        public static function prepareCriteriaForSave($criteria)
        {
            
    $criteria self::unserializeCriteria($criteria);

            
    $criteriaPreSave = array();
            foreach (
    $criteria AS $itemCriteria)
            {
                if (!empty(
    $itemCriteria['rule']))
                {
                    if (empty(
    $itemCriteria['data']) || !is_array($itemCriteria['data']))
                    {
                        
    $itemCriteria['data'] = array();
                    }

                    
    $criteriaPreSave[] = array(
                        
    'rule' => $itemCriteria['rule'],
                        
    'data' => $itemCriteria['data']
                    );
                }
            }
            return 
    $criteriaPreSave;
        }
    Next, when a user visits the shop page, each items criteria (if any), is prepared to be checked against:

    PHP:
        public static function prepareCriteriaForSelection($criteria)
        {
            
    $criteria self::unserializeCriteria($criteria);

            
    $output = array();
            foreach (
    $criteria AS $itemCriteria)
            {
                
    $data = (!empty($itemCriteria['data']) ? $itemCriteria['data'] : true);
                
    $output[$itemCriteria['rule']] = $data;
            }
            return 
    $output;
        }
    after that, the criteria for the item is checked against the users data (usergroup, user id, created character class, race, gender, etc). Below is a snippet of the code I use. All I want is a true or false to be returned as quickly as possible.

    PHP:
        public static function charMatchesCriteria($criteria, array $charData null$visitorsName ''$secondaryGroups '')
        {
            if (!
    $criteria self::unserializeCriteria($criteria))
            {
                return 
    true// no criteria
            
    }

            foreach (
    $criteria AS $criterion)
            {
                
    $data $criterion['data'];

                switch (
    $criterion['rule'])
                {
                    case 
    'username':
                        if (
    utf8_strtolower($data['name']) != utf8_strtolower($visitorsName))
                        {
                            return 
    false;
                        }
                        else
                        {
                            return 
    true// made for a member, no other criteria matters
                        
    }
                    break;
                    case 
    'usergroup':
                        
    $secondaryGroups = ($secondaryGroups explode(','$secondaryGroups) : array());

                        if (!
    in_array($data['user_group_id'], $secondaryGroups))
                        {
                            return 
    false;
                        }
                    break;
                    case 
    'strength_score':
                    case 
    'dexterity_score':
                    case 
    'constitution_score':
                    case 
    'intelligence_score':
                    case 
    'wisdom_score':
                    case 
    'charisma_score':
                        
    $abilityKey substr($criterion['rule'], 0strlen($criterion['rule']) -6);

                        if (
    $charData['iwd_stats'][$abilityKey]['score'] < $data['score'])
                        {
                            return 
    false;
                        }
                    break;

    ... and 
    a few more checks...
    For each item a user may be able to purchase, the above check is done. If false, the item can not be selected for purchase (or is not visible depending if it is made for a specific usergroup or person), if true, it is displayed for possible purchase.

    Just a note: I do not use any template helpers for criteria checks as they are completed before the data is sent to the appropriate template.

    I don't know if the above will help, as it is used for page callbacks (to generate a list of displayed-able items for purchase), and then again for the controller public part to ensure a user is not trying to cheat.
     

Share This Page