Skip to content
Snippets Groups Projects
Commit 307d7108 authored by Reinhold Kainhofer's avatar Reinhold Kainhofer
Browse files

Implement custom variable definitions

-) Implement custom definitions (Variable or Definition as keyword) of the form:
    Variable|Definition=VARNAME; [Value=]SOMECOMPLEXVALUE
-) Such defined variables can be used in all further rules.
-) Add "Condition=" keyword to indicate that a certain value is a condition (e.g. a variable defined as implemented here).
   This is needed to distinguish single-variable (or function-call) conditions from shipping costs, where the "Shipping=" was left out.
   Previously, only terms that contained a comparison operator were detected to be conditions. This excluded conditions like
   "issubset(...)" or "MyZIPConditions" (i.e. functions returning boolean values and boolean values stored in variables).
-) The rule-matching code was moved to its own function, so the logic to distinguish variable definitions and (later on) modifiers
   is in only one place.
parent c7964557
No related branches found
No related tags found
No related merge requests found
...@@ -152,7 +152,7 @@ class ShippingRule_Advanced extends ShippingRule { ...@@ -152,7 +152,7 @@ class ShippingRule_Advanced extends ShippingRule {
// Special-case the name assignment, where we don't want to interpret the value as an arithmetic expression! // Special-case the name assignment, where we don't want to interpret the value as an arithmetic expression!
if (preg_match('/^\s*(name)\s*=\s*(["\']?)(.*)\2\s*$/i', $rulepart, $matches)) { if (preg_match('/^\s*(name|variable|definition)\s*=\s*(["\']?)(.*)\2\s*$/i', $rulepart, $matches)) {
$this->handleAssignment ($matches[1], $matches[3], $rulepart); $this->handleAssignment ($matches[1], $matches[3], $rulepart);
return; return;
} }
...@@ -389,20 +389,21 @@ class ShippingRule_Advanced extends ShippingRule { ...@@ -389,20 +389,21 @@ class ShippingRule_Advanced extends ShippingRule {
// 5a) // 5a)
if (count($stack) != 1) { if (count($stack) != 1) {
JFactory::getApplication()->enqueueMessage(JText::sprintf('VMSHIPMENT_RULES_EVALUATE_UNKNOWN_ERROR', $rulepart), 'error'); JFactory::getApplication()->enqueueMessage(JText::sprintf('VMSHIPMENT_RULES_EVALUATE_UNKNOWN_ERROR', $rulepart), 'error');
JFactory::getApplication()->enqueueMessage(JText::sprintf('Outstack: <pre>%s</pre>', print_r($out_stack,1)), 'error');
$stack = array (0); $stack = array (0);
} }
$res = array_pop($stack); // 5) $res = array_pop($stack); // 5)
if ($is_condition) { // Comparisons are conditions if ($is_assignment) { // Assignments are handled first, so conditions can be assigned to variables
$this->conditions[] = $res;
} elseif ($is_assignment) {
if ($res[0]=='=') { if ($res[0]=='=') {
$this->handleAssignment ($res[1], $res[2], $rulepart); $this->handleAssignment ($res[1], $res[2], $rulepart);
} else { } else {
// Assignment has to be top-level! // Assignment has to be top-level!
JFactory::getApplication()->enqueueMessage(JText::sprintf('VMSHIPMENT_RULES_EVALUATE_ASSIGNMENT_TOPLEVEL', $rulepart), 'error'); JFactory::getApplication()->enqueueMessage(JText::sprintf('VMSHIPMENT_RULES_EVALUATE_ASSIGNMENT_TOPLEVEL', $rulepart), 'error');
} }
} elseif ($is_condition) { // Comparisons are conditions
$this->conditions[] = $res;
} else { } else {
// Terms without comparisons or assignments are shipping cost expressions // Terms without comparisons or assignments are shipping cost expressions
$this->shipping = $res; $this->shipping = $res;
......
...@@ -224,6 +224,48 @@ class plgVmShipmentRules_Shipping_Base extends vmPSPlugin { ...@@ -224,6 +224,48 @@ class plgVmShipmentRules_Shipping_Base extends vmPSPlugin {
protected function findMatchingRule (&$cartvals, $method) {
$result = array("rule"=>Null, "rule_name"=>"", "modifiers"=>array());
// TODO: Handle modifiers
foreach ($method->rules as $r) {
// If the rule is a variable definition, it will NOT match, but modify the $cartvals array for the next rules
if ($r->matches($cartvals)) {
$result["rule"] = $r;
$result["rule_name"] = $r->getRuleName($cartvals);
return $result;
}
}
// None of the rules matched, so return NULL;
return NULL;
}
/**
* @param \VirtueMartCart $cart
* @param int $method
* @param array $cart_prices
* @return bool
*/
protected function checkConditions ($cart, $method, $cart_prices) {
if (!isset($method->rules)) $this->parseMethodRules($method);
$cartvals = $this->getCartValues ($cart, $method, $cart_prices);
$match = $this->findMatchingRule ($cartvals, $method);
if ($match) {
$method->matched_rule = $match["rule"];
$method->rule_name = $match["rule_name"];
// If NoShipping is set, this method should NOT offer any shipping at all, so return FALSE, otherwise TRUE
if ($method->matched_rule->isNoShipping()) {
$this->printWarning(JText::sprintf('VMSHIPMENT_RULES_NOSHIPPING_MESSAGE', $method->rule_name));
vmdebug('checkConditions '.$method->shipment_name.' indicates NoShipping for rule "'.$method->rule_name.'" ('.$method->matched_rule->rulestring.').');
return FALSE;
} else {
return TRUE;
}
}
vmdebug('checkConditions '.$method->shipment_name.' does not fit');
return FALSE;
}
/** /**
* @param VirtueMartCart $cart * @param VirtueMartCart $cart
* @param $method * @param $method
...@@ -233,18 +275,17 @@ class plgVmShipmentRules_Shipping_Base extends vmPSPlugin { ...@@ -233,18 +275,17 @@ class plgVmShipmentRules_Shipping_Base extends vmPSPlugin {
function getCosts (VirtueMartCart $cart, $method, $cart_prices) { function getCosts (VirtueMartCart $cart, $method, $cart_prices) {
if (!isset($method->rules)) $this->parseMethodRules($method); if (!isset($method->rules)) $this->parseMethodRules($method);
$cartvals = $this->getCartValues ($cart, $method, $cart_prices); $cartvals = $this->getCartValues ($cart, $method, $cart_prices);
$match = $this->findMatchingRule ($cartvals, $method);
foreach ($method->rules as $r) { if ($match) {
if ($r->matches($cartvals)) { $r = $match["rule"];
$rulename=$r->getRuleName($cartvals); $rulename = $match["rule_name"];
vmdebug('Rule '.$rulename.' ('.$r->rulestring.') matched.'); vmdebug('Rule '.$rulename.' ('.$r->rulestring.') matched.');
$method->tax_id = $r->tax_id; $method->tax_id = $r->tax_id;
$method->matched_rule = $r; $method->matched_rule = $r;
$method->rule_name = $r->getRuleName($cartvals); $method->rule_name = $rulename;
$method->cost = $r->getShippingCosts($cartvals); $method->cost = $r->getShippingCosts($cartvals);
$method->includes_tax = $r->includes_tax; $method->includes_tax = $r->includes_tax;
return $method->cost; return $method->cost;
}
} }
vmdebug('getCosts '.$method->name.' does not return shipping costs'); vmdebug('getCosts '.$method->name.' does not return shipping costs');
...@@ -530,35 +571,6 @@ class plgVmShipmentRules_Shipping_Base extends vmPSPlugin { ...@@ -530,35 +571,6 @@ class plgVmShipmentRules_Shipping_Base extends vmPSPlugin {
return $cartvals; return $cartvals;
} }
/**
* @param \VirtueMartCart $cart
* @param int $method
* @param array $cart_prices
* @return bool
*/
protected function checkConditions ($cart, $method, $cart_prices) {
if (!isset($method->rules)) $this->parseMethodRules($method);
$cartvals = $this->getCartValues ($cart, $method, $cart_prices);
foreach ($method->rules as $r) {
if ($r->matches($cartvals)) {
$method->matched_rule = $r;
$method->rule_name = $r->getRuleName($cartvals);
// If NoShipping is set, this method should NOT offer any shipping at all, so return FALSE, otherwise TRUE
if ($r->isNoShipping()) {
$this->printWarning(JText::sprintf('VMSHIPMENT_RULES_NOSHIPPING_MESSAGE', $method->rule_name));
vmdebug('checkConditions '.$method->shipment_name.' indicates NoShipping for rule "'.$method->rule_name.'" ('.$r->rulestring.').');
return FALSE;
} else {
return TRUE;
}
}
}
vmdebug('checkConditions '.$method->shipment_name.' does not fit');
return FALSE;
}
/** /**
* Create the table for this plugin if it does not yet exist. * Create the table for this plugin if it does not yet exist.
* This functions checks if the called plugin is active one. * This functions checks if the called plugin is active one.
...@@ -683,6 +695,7 @@ class ShippingRule { ...@@ -683,6 +695,7 @@ class ShippingRule {
var $shipping = 0; var $shipping = 0;
var $includes_tax = 0; var $includes_tax = 0;
var $name = ''; var $name = '';
var $is_definition = 0;
function __construct ($rule, $countries, $tax_id) { function __construct ($rule, $countries, $tax_id) {
if (is_array($countries)) { if (is_array($countries)) {
...@@ -704,10 +717,14 @@ class ShippingRule { ...@@ -704,10 +717,14 @@ class ShippingRule {
function handleAssignment ($var, $value, $rulepart) { function handleAssignment ($var, $value, $rulepart) {
switch (strtolower($var)) { switch (strtolower($var)) {
case 'name': $this->name = $value; break;
case 'shipping': $this->shipping = $value; $this->includes_tax = False; break; case 'shipping': $this->shipping = $value; $this->includes_tax = False; break;
case 'shippingwithtax': $this->shipping = $value; $this->includes_tax = True; break; case 'shippingwithtax': $this->shipping = $value; $this->includes_tax = True; break;
case 'name': $this->name = $value; break; case 'variable': // Variable=... is the same as Definition=...
case 'definition': $this->name = $value; $this->is_definition = True; break;
case 'value': $this->shipping = $value; break; // definition values are also stored in the shipping member!
case 'comment': break; // Completely ignore all comments! case 'comment': break; // Completely ignore all comments!
case 'condition': $this->conditions[] = $value; break;
default: JFactory::getApplication()->enqueueMessage(JText::sprintf('VMSHIPMENT_RULES_UNKNOWN_VARIABLE', $var, $rulepart), 'error'); default: JFactory::getApplication()->enqueueMessage(JText::sprintf('VMSHIPMENT_RULES_UNKNOWN_VARIABLE', $var, $rulepart), 'error');
} }
} }
...@@ -951,24 +968,29 @@ class ShippingRule { ...@@ -951,24 +968,29 @@ class ShippingRule {
return $this->evaluateTerm($this->shipping, $vals); return $this->evaluateTerm($this->shipping, $vals);
} }
function matches($vals) { function matches(&$vals) {
// First, check the country, if any conditions are given: // First, check the country, if any conditions are given:
if (count ($this->countries) > 0 && !in_array ($vals['countryid'], $this->countries)) { if (count ($this->countries) > 0 && !in_array ($vals['countryid'], $this->countries)) {
// vmdebug('Rule::matches: Country check failed: countryid='.print_r($vals['countryid'],1).', countries are: '.print_r($this->countries,1).'...'); // vmdebug('Rule::matches: Country check failed: countryid='.print_r($vals['countryid'],1).', countries are: '.print_r($this->countries,1).'...');
return False; return False;
} }
foreach ($this->conditions as $c) { foreach ($this->conditions as $c) {
// All conditions have to match! // All conditions have to match!
$ret = $this->evaluateTerm($c, $vals); $ret = $this->evaluateTerm($c, $vals);
// JFactory::getApplication()->enqueueMessage("Evaluating term <pre>".print_r($c,1)."</pre> returns $ret", 'error');
if (is_null($ret) || (!$ret)) { if (is_null($ret) || (!$ret)) {
return false; return false;
} }
} }
// All conditions match, so return true // All conditions match, so return true for rules; For definitions add the variable to the vals
return true; if ($this->is_definition) {
$vals[$this->name] = $this->evaluateTerm($this->shipping, $vals);
// This rule does not specify shipping costs (just modify the cart values!), so return false
return false;
} else {
return true;
}
} }
function getRuleName($vals) { function getRuleName($vals) {
...@@ -994,6 +1016,9 @@ class ShippingRule { ...@@ -994,6 +1016,9 @@ class ShippingRule {
// NoShipping is set, so if the rule matches, this method should not offer any shipping at all // NoShipping is set, so if the rule matches, this method should not offer any shipping at all
return (is_string($this->shipping) && (strtolower($this->shipping)=="noshipping")); return (is_string($this->shipping) && (strtolower($this->shipping)=="noshipping"));
} }
function isDefinition() {
return $this->is_definition;
}
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment