Dan
Dan

Reputation: 1559

Using comparison operators stored in an array

I have the following example array:

$comparisons = array(
    0 => array(
        'method'    => 'productTotalQuantity',
        'operator'  => '>=',
        'value'     => '2'
    ),
    1 => array(
        'method'    => 'productTotalWeight',
        'operator'  => '<=',
        'value'     => '10'
    )
);

I have invented this array structure, so it can be altered if required. I am trying to somehow evaluate the operator key, so that I can achieve something along the lines of:

foreach ($comparisons as $comparison) {
    $value = $this->$comparison['method']($product);
    // E.g. $value = $this->productTotalQuantity($product)
    // $value could = 4

    if ($value $comparison['operator'] $comparison['value']) {
        // Comparison successful
        $matches[] = TRUE;
    }
}

if (count($matches) == count($comparisons)) {
    // All comparisons were successful. Apply the discount.
}

If you have time, a full code example of how to parse this array would be extremely helpful. I've been working on it for about 20 hours straight and think I'm about to literally bash my head against a brick wall. If you are familiar with Magento, I am trying to somewhat mimic the functionality of the "Shopping Cart Price Rule" Conditions in Promotions.

Upvotes: 0

Views: 172

Answers (3)

abcde123483
abcde123483

Reputation: 3905

<?php

$ge = function($a, $b) {return($a >= $b);};
$le = function($a, $b) {return($a <= $b);};

$comparisons = array(
    array(
        'method'    => 'productTotalQuantity',
        'operator'  => $ge,
        'value'     => 2
    ),
    array(
        'method'    => 'productTotalWeight',
        'operator'  => $le,
        'value'     => 10
    )
);

// finds out if discount should be applied in this price range
function discount_finder($myval, $comparisons) {
    $discount = TRUE;
    foreach($comparisons as $comp) {
        if (!$comp['operator']($myval, $comp['value'])) {
            $discount = FALSE;
            $break;
        }
    }
    return $discount;
}

$discount = discount_finder(1, $comparisons);
if ($discount == TRUE) {  // apply discount
    echo "Discount applied!!!\n";
} else {
    echo "no discount!\n";
}

$discount = discount_finder(6, $comparisons);
if ($discount == TRUE) {  // apply discount
    echo "Discount applied!!!\n";
} else {
    echo "no discount!\n";
}

$discount = discount_finder(13, $comparisons);
if ($discount == TRUE) {  // apply discount
    echo "Discount applied!!!\n";
} else {
    echo "no discount!\n";
}

?>

Upvotes: 0

strauberry
strauberry

Reputation: 4199

"translating" operations from strings to real operations is mostly dirty and or evil :-) you need a lot of conditional code (if-else) or eval (but everybody knows: eval is evil ^^)

I would use an object-oriented approach, since PHP does support object orientation (I don't know the exact php syntax, it has been a while ;-)) and I give you pseudo code to enforce the ideas:

class AbstractComparator {
   boolean static compare($operand1, $operand2);   
}

class EqualsComparator extends AbstractComparator {
   @Override
   boolean static compare($operand1, $operand2) {
      return ($operand1 == $operand2);
   }
}

// Now use one of the subclasses in your datastructure
$comparisons = array(
0 => array(
    'method'    => 'productTotalQuantity',
    'operator'  => EqualsComparator,
    'value'     => '2'
),
1 => array(
    'method'    => 'productTotalWeight',
    'operator'  => SmallerThanComparator,
    'value'     => '10'
)
);

$allComparisonsSuccessful = true;
foreach ($comparisons as $comparison) {
   $value = $comparison['operator'].equals($product);
    // Use the AND operator... full predicate is only true if all elements are true
   $allComparisonsSuccessful = $allComparisonsSuccessful && $value;
}

Upvotes: 4

kba
kba

Reputation: 19476

This would be an easy job for eval(). Unfortunately, there's an important rule about when to use eval() which is: Never do it.

So instead you could introduce a method like this

function parseComparison($comparison)
{
    list($methodValue,$operator,$value);
    switch ($operator)
    {
        case '>=': return $methodValue >= $value;
        case '<=': return $methodValue <= $value;
        case '>':  return $methodValue >  $value;
        case '<':  return $methodValue <  $value;
        default: return false;
    }
}

Upvotes: 1

Related Questions