From 4acc904cb025d2d92b894ac6bd23f0b02201df3b Mon Sep 17 00:00:00 2001
From: Reinhold Kainhofer <reinhold@kainhofer.com>
Date: Fri, 11 Jan 2013 17:47:59 +0100
Subject: [PATCH] Version 1.6.2: Remove callback class and instead directly
 loop through all replacements

Restructure code to get away from the helper class, instead create explicit list of replacements
---
 Makefile                                      |   2 +-
 ordernumber.php                               | 173 ++++++++----------
 ordernumber.script.php                        |   6 +-
 ordernumber.xml                               |   4 +-
 releases/plg_vmshopper_ordernumber_v1.6.2.zip | Bin 0 -> 9979 bytes
 5 files changed, 87 insertions(+), 98 deletions(-)
 create mode 100644 releases/plg_vmshopper_ordernumber_v1.6.2.zip

diff --git a/Makefile b/Makefile
index 38addfd..c426d94 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 BASE=ordernumber
 PLUGINTYPE=vmshopper
-VERSION=1.6.1
+VERSION=1.6.2
 
 PLUGINFILES=$(BASE).php $(BASE).script.php $(BASE).xml index.html
 # TRANSDIR=../../../administrator/language/
diff --git a/ordernumber.php b/ordernumber.php
index ea08c77..a5b51ee 100644
--- a/ordernumber.php
+++ b/ordernumber.php
@@ -10,75 +10,6 @@
 defined('_JEXEC') or     die( 'Direct Access to ' . basename( __FILE__ ) . ' is not allowed.' ) ;
 if (!class_exists('vmShopperPlugin')) require(JPATH_VM_PLUGINS . DS . 'vmshopperplugin.php');
 
-/* For php 5.2 we cannot use lambda functions or any other way to pass local variables to the callback.
-   The only way to pass a local variable to a callback for preg_replace_callback is to 
-   create a class instance... */
-class ReplacementCallback {
-    private $details;
-    private $nrtype;
-
-    function __construct($nrtype, $details) {
-        $this->details = $details;
-        $this->nrtype = $nrtype;
-    }
-
-    /* Return a random "string" of the given length taken from the given alphabet */
-    static function randomString($alphabet, $len) {
-        $alen = strlen($alphabet);
-        $r = "";
-        for ($n=0; $n<$len; $n++) {
-            $r .= $alphabet[mt_rand(0, $alen-1)];
-        }
-        return $r;
-    }
-
-    function replace ($match) {
-        $varname = strtolower($match[1]);
-        switch ($varname) {
-            case "year":  return date ("Y");
-            case "year2": return date ("y");
-            case "month": return date("m");
-            case "day": return date("d");
-            case "hour": return date("H");
-            case "hour12": return date("h");
-            case "ampm": return date("a");
-            case "minute": return date("i");
-            case "second": return date("s");
-            case "random":
-                /* the regexp matches (random)(Type)(Len) as match 1 to 3, Len is optional */
-                $len = ($match[3]?$match[3]:1);
-                // Fallback: If no Type is given, use Digit
-                $alphabet = "0123456789";
-                // Select the correct alphabet depending on Type
-                switch (strtolower($match[2])) {
-                    case "digit": $alphabet = "0123456789"; break;
-                    case "hex": $alphabet = "0123456789abcdef"; break;
-                    case "letter": $alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; break;
-                    case "uletter": $alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; break;
-                    case "lletter": $alphabet = "abcdefghijklmnopqrstuvwxyz"; break;
-                    case "alphanum": $alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; break;
-                }
-                return self::randomString ($alphabet, $len);
-            case "vendorid": return ($this->details->virtuemart_vendor_id);
-            case "userid": return ($this->details->virtuemart_user_id);
-            case "ipaddress": return ($this->details->ip_address);
-
-            // Only for Invoice:
-            case "ordernumber": return ($this->details->order_number);
-            case "orderid": return ($this->details->virtuemart_order_id);
-            case "lastname": return ($this->details->last_name);
-            case "firstname": return ($this->details->first_name);
-            case "company": return ($this->details->company);
-            case "city": return ($this->details->city);
-            case "zip": return ($this->details->zip);
-            case "orderstatus": return ($this->details->order_status);
-        }
-        // No variable type matched, so don't replace, return the original string
-        return $match[0];
-    }
-}
-
-
 class plgVmShopperOrdernumber extends vmShopperPlugin {
 
     function __construct(& $subject, $config) {
@@ -104,29 +35,85 @@ class plgVmShopperOrdernumber extends vmShopperPlugin {
 
     // We don't need this function, but the parent class declares it abstract, so we need to overload
     function plgVmOnUpdateOrderBEShopper($_orderID) {}
+    
+    /* Return a random "string" of the given length taken from the given alphabet */
+    static function randomString($alphabet, $len) {
+        $alen = strlen($alphabet);
+        $r = "";
+        for ($n=0; $n<$len; $n++) {
+            $r .= $alphabet[mt_rand(0, $alen-1)];
+        }
+        return $r;
+    }
+
+    function replaceRandom ($match) {
+        /* the regexp matches (random)(Type)(Len) as match, Type and Len is optional */
+        $len = ($match[3]?$match[3]:1);
+        // Fallback: If no Type is given, use Digit
+        $alphabet = "0123456789";
+        // Select the correct alphabet depending on Type
+        switch (strtolower($match[2])) {
+            case "digit": $alphabet = "0123456789"; break;
+            case "hex": $alphabet = "0123456789abcdef"; break;
+            case "letter": $alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; break;
+            case "uletter": $alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; break;
+            case "lletter": $alphabet = "abcdefghijklmnopqrstuvwxyz"; break;
+            case "alphanum": $alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; break;
+        }
+        return self::randomString ($alphabet, $len);
+    }
+
 
-    /* Replace the format variables, match[1] is the variable name, match[2] and match[3] are only used for random fields */
     /* Type 0 means order number, type 1 means invoice number, type 2 means customer number, 3 means order password */
     function replace_fields ($fmt, $nrtype, $details) {
-        // Match variables for the form random[type][count] and everything else.
-        // This makes it possible to handle "random" just like any other type!
-        $patterns = array (
-            '/\[(random)(.*?)([0-9]*?)\]/', // For randomTypeN, spit the three parts
-            '/\[([^\]]+)\]/'   // Everything else matches whole variable name
+        // First, replace all randomXXX[n] fields. This needs to be done with a regexp and a callback:
+        $fmt = preg_replace_callback ('/\[(random)(.*?)([0-9]*?)\]/', array($this, 'replaceRandom'), $fmt);
+        
+        $reps = array (
+            "[year]" => date ("Y"),
+            "[year2]" => date ("y"),
+            "[month]" => date("m"),
+            "[day]" => date("d"),
+            "[hour]" => date("H"),
+            "[hour12]" => date("h"),
+            "[ampm]" => date("a"),
+            "[minute]" => date("i"),
+            "[second]" => date("s"),
+            "[userid]" => $details->virtuemart_user_id,
+            "[vendorid]" => $details->virtuemart_vendor_id
         );
-//         // TODO: in  php 5.3 and 5.4 we can easier pass $orderDetails to the callback
-//         function my_callback ($match) {
-//             return self::replacementCallback ($match, $details); 
-//         };
-//         return preg_replace_callback ($patterns, 
-//             function ($match) use ($details) { 
-//                 return self::replacementCallback ($match, $details); 
-//             }, $fmt);
-
-        /* php 5.2 does not allow lambda functions and there is no other way to
-           pass a local variable to the callback than a class instance! */
-        $callback = new ReplacementCallback ($nrtype, $details);
-        return preg_replace_callback ($patterns, array($callback, 'replace'), $fmt);
+        if ($nrtype==0 or $nrtype == 1) {
+            $reps["[ipaddress]"] = $details->ip_address;
+        }
+        if ($nrtype==1) {
+            // Only for Invoice:
+            $reps["[ordernumber]"] = $details->order_number;
+            $reps["[orderid]"] = $details->virtuemart_order_id;
+            $reps["[lastname]"] = $details->last_name;
+            $reps["[firstname]"] = $details->first_name;
+            $reps["[company]"] = $details->company;
+            $reps["[city]"] = $details->city;
+            $reps["[zip]"] = $details->zip;
+            $reps["[orderstatus]"] = $details->order_status;
+        }
+        if ($nrtype==2) {
+            // Customer number:
+            print_r($details);
+            $reps["[username]"] = $details->username;
+            $reps["[name]"] = $details->name;
+            $reps["[email]"] = $details->email;
+            $reps["[company]"] = $details->company;
+            $reps["[title]"] = $details->title;
+            $reps["[firstname]"] = $details->first_name;
+            $reps["[middlename]"] = $details->middle_name;
+            $reps["[lastname]"] = $details->last_name;
+            $reps["[zip]"] = $details->zip;
+            $reps["[city]"] = $details->city;
+            $reps["[countryid]"] = $details->virtuemart_country_id;
+            $reps["[stateid]"] = $details->virtuemart_state_id;
+            $reps["[user_is_vendor]"] = $details->user_is_vendor;
+        }
+        return str_ireplace (array_keys($reps), array_values($reps), $fmt);
     }
 
     /* Type 0 means order number, type 1 means invoice number, type 2 means customer number */
@@ -154,7 +141,6 @@ class plgVmShopperOrdernumber extends vmShopperPlugin {
         $db->query();
 
         // return the format with the counter inserted
-        
         return str_replace ("#", sprintf('%0' . $padding . 's', $count), $nr);
     }
 
@@ -162,7 +148,7 @@ class plgVmShopperOrdernumber extends vmShopperPlugin {
     function plgVmOnUserOrder(&$orderDetails/*,&$data*/) {
         // Is order number customization enabled?
         if ($this->params->get('customize_order_number')) {
-          $nrtype=0; /*order-nr*/
+          $nrtype = 0; /*order-nr*/
           $fmt = $this->params->get ('order_number_format', "#");
           $global = $this->params->get ('order_number_global', 1);
           $padding = $this->params->get ('order_number_padding', 1);
@@ -171,8 +157,9 @@ class plgVmShopperOrdernumber extends vmShopperPlugin {
         }
         // Is order password customization enabled?
         if ($this->params->get('customize_order_password')) {
+          $nrtype = 3; /* order password */
           $fmt = $this->params->get ('order_password_format', "[randomHex8]");
-          $passwd = $this->replace_fields ($fmt, 3, $orderDetails);
+          $passwd = $this->replace_fields ($fmt, $nrtype, $orderDetails);
           $orderDetails->order_pass = $passwd;
         }
     }
@@ -186,7 +173,7 @@ class plgVmShopperOrdernumber extends vmShopperPlugin {
             $pdfInvoice = (int)VmConfig::get('pdf_invoice', 0); // backwards compatible
             $force_create_invoice=JRequest::getInt('create_invoice', 0);
             if ( in_array($orderDetails['order_status'],$orderstatusForInvoice)  or $pdfInvoice==1  or $force_create_invoice==1 ){
-                $nrtype=1; /*invoice-nr*/
+                $nrtype = 1; /*invoice-nr*/
                 $fmt = $this->params->get ('invoice_number_format', "#");
                 $global = $this->params->get ('invoice_number_global', 1);
                 $padding = $this->params->get ('invoice_number_padding', 1);
@@ -202,7 +189,7 @@ class plgVmShopperOrdernumber extends vmShopperPlugin {
     function plgVmOnUserStore(&$data) {
         // Is order number customization enabled?
         if ($this->params->get('customize_customer_number') && isset($data['customer_number_bycore']) && $data['customer_number_bycore']==1) {
-            $nrtype=2; /*customer-nr*/
+            $nrtype = 2; /*customer-nr*/
             $fmt = $this->params->get ('customer_number_format', "#");
             $global = $this->params->get ('customer_number_global', 1);
             $padding = $this->params->get ('customer_number_padding', 1);
diff --git a/ordernumber.script.php b/ordernumber.script.php
index d7146b7..cbbd586 100644
--- a/ordernumber.script.php
+++ b/ordernumber.script.php
@@ -57,8 +57,10 @@ class plgVmShopperOrdernumberInstallerScript
     public function update(JAdapterInstance $adapter)
     {
         jimport( 'joomla.filesystem.file' ); 
-        JFile::delete( JPATH_ROOT . DS . "administrator" . DS . "language" . DS . "en-GB" . DS . "en-GB.plg_vmshopper_ordernumber.sys.ini"); 
-        JFile::delete( JPATH_ROOT . DS . "administrator" . DS . "language" . DS . "de-DE" . DS . "de-DE.plg_vmshopper_ordernumber.sys.ini"); 
+        $file = JPATH_ROOT . DS . "administrator" . DS . "language" . DS . "en-GB" . DS . "en-GB.plg_vmshopper_ordernumber.sys.ini";
+        if (JFile::exists($file)) JFile::delete($file); 
+        $file = JPATH_ROOT . DS . "administrator" . DS . "language" . DS . "de-DE" . DS . "de-DE.plg_vmshopper_ordernumber.sys.ini"; 
+        if (JFile::exists($file)) JFile::delete($file); 
         return true;
     }
  
diff --git a/ordernumber.xml b/ordernumber.xml
index ca874ed..2f6128a 100644
--- a/ordernumber.xml
+++ b/ordernumber.xml
@@ -7,8 +7,8 @@
     <authorUrl>http://www.kainhofer.com/</authorUrl>
     <copyright>Copyright (C) 2012-2013 Reinhold Kainhofer. All rights reserved.</copyright>
     <license>http://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3</license>
-    <version>1.6.1</version>
-    <releaseDate>2013-01-09</releaseDate>
+    <version>1.6.2</version>
+    <releaseDate>2013-01-11</releaseDate>
     <releaseType>Minor update</releaseType>
     <downloadUrl>http://www.kainhofer.com/virtuemart-2-extensions/vm2-ordernumber-plugin.html</downloadUrl>
 
diff --git a/releases/plg_vmshopper_ordernumber_v1.6.2.zip b/releases/plg_vmshopper_ordernumber_v1.6.2.zip
new file mode 100644
index 0000000000000000000000000000000000000000..6669f863eab81c38ad3d053fad0fff03622d5cce
GIT binary patch
literal 9979
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

literal 0
HcmV?d00001

-- 
GitLab