From dd3f569ede8ee53737d0643a515dfd3a2084e934 Mon Sep 17 00:00:00 2001
From: Laurent Destailleur <eldy@destailleur.fr>
Date: Fri, 6 Mar 2015 20:34:00 +0100
Subject: [PATCH] NEW: Enhance the natural_search function so we can use it to
 search numeric fields with criteria with operator <>= inside (< 100, >= 1000)

---
 htdocs/core/lib/functions.lib.php | 68 ++++++++++++++++++++++---------
 1 file changed, 49 insertions(+), 19 deletions(-)

diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index 438f0ee22ca..c5d8d509b08 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -4946,34 +4946,64 @@ function dol_getmypid()
 
 
 /**
- * Natural search
- *
- * @param 	mixed 	$fields 	String or array of strings filled with the fields names in the SQL query
- * @param 	string 	$value 		The value to look for (example: "keyword1 keyword2")
- * @return 	string 	$res 		The statement to append to the SQL query
- */
-function natural_search($fields, $value)
-{
-    global $db;
+ * Generate natural SQL search string
+ *
+ * @param 	string|string[]	$fields 	String or array of strings, filled with the name of fields in the SQL query
+ * @param 	string 			$value 		The value to look for. 
+ *                          		    If param $numeric is 0, can contains several keywords separated with a space, like "keyword1 keyword2" = We want record field like keyword1 and field like keyword2
+ *                             			If param $numeric is 1, can contains an operator <>= like "<10" or ">=100.5 < 1000"
+ * @param	string			$number		0=value is list of keywords, 1=value is a numeric test
+ * @return 	string 			$res 		The statement to append to the SQL query
+ */
+function natural_search($fields, $value, $numeric=0)
+{
+    global $db,$langs;
+    
+    if ($numeric)
+    {
+    	$value=preg_replace('/([<>=]+)\s([0-9'.preg_quote($langs->trans("DecimalSeparator"),'/').'])/','\1\2',$value);	// Clean string '< 10' into '<10' so we can the explode on space to get all tests to do
+    }
     $crits = explode(' ', $value);
     $res = '';
     if (! is_array($fields)) $fields = array($fields);
 
-    $end = count($fields);
+    $nboffields = count($fields);
     $end2 = count($crits);
     $j = 0;
-    foreach ($crits as $crit) {
-        $i = 0;
-        foreach ($fields as $field) {
-            if ( $i > 0 && $i < $end) $res .= " OR ";
-            $res .= $field . " LIKE '%" . $db->escape(trim($crit)) . "%'";
+    foreach ($crits as $crit) 
+    {
+        $i = 0; $i2 = 0;
+        $newres = '';
+        foreach ($fields as $field) 
+        {
+            if ($numeric) 
+            {
+            	$operator='=';
+            	$newcrit = preg_replace('/([<>=]+)/','',trim($crit));
+            	
+            	preg_match('/([<>=]+)/',trim($crit), $reg);
+            	if ($reg[1]) 
+            	{
+            		$operator = $reg[1];
+            	}
+            	if ($newcrit != '')
+            	{
+            		$newres .= ($i2 > 0 ? ' OR ' : '') . $field . ' '.$operator.' '.price2num($newcrit);
+            		$i2++;	// a criteria was added to string
+            	}
+            }
+            else 
+            {
+            	$newres .= ($i2 > 0 ? ' OR ' : '') . $field . " LIKE '%" . $db->escape(trim($crit)) . "%'";
+            	$i2++;	// a criteria was added to string
+            }
             $i++;
         }
-        if ($end > 1) $res .= ')';
-        if ($j < $end2 - 1) $res .= " AND ";
-        if ($end > 1 && $j < $end2 - 1) $res .= '(';
+        if ($newres) $res = $res . ($res ? ' AND ' : '') . ($i2 > 1 ? '(' : '') .$newres . ($i2 > 1 ? ')' : '');
         $j++;
     }
-    return " AND " . ($end > 1? '(' : '') . $res;
+    $res = " AND (" . $res . ")";
+    //print 'xx'.$res.'yy';
+    return $res;
 }
 
-- 
GitLab