From c53ece2a2d221ae6ee7b58ab9568ace2c4cb0f99 Mon Sep 17 00:00:00 2001
From: Llewellyn van der Merwe <llewellyn@vdm.io>
Date: Fri, 16 Sep 2022 23:41:41 +0200
Subject: [PATCH] Adds more classes, and refactoring to the search feature.
 Adds test search to search page. #952

---
 README.md                                     |   8 +-
 admin/README.txt                              |   8 +-
 .../en-GB/en-GB.com_componentbuilder.ini      |   1 -
 admin/models/ajax.php                         |  16 +-
 admin/views/search/tmpl/default.php           |  25 +-
 componentbuilder.xml                          |   2 +-
 .../src/Componentbuilder/Search/Agent.php     |   2 +-
 .../Componentbuilder/Search/Agent/Replace.php |   2 +-
 .../Componentbuilder/Search/Agent/Search.php  | 253 ++++++++++++++++--
 .../Componentbuilder/Search/Agent/Update.php  | 115 ++++++--
 .../src/Componentbuilder/Search/Config.php    |   8 +-
 .../Search/Interfaces/FindInterface.php       |   3 +-
 .../Search/Interfaces/ModelInterface.php      |  10 +-
 .../Search/Interfaces/SearchInterface.php     |  56 ++++
 .../Search/Interfaces/SearchTypeInterface.php |  43 +++
 .../src/Componentbuilder/Search/Model.php     |  51 +++-
 .../src/Componentbuilder/Search/Model/Get.php |  10 +-
 .../Componentbuilder/Search/Service/Agent.php |   6 +-
 .../Search/Service/Search.php                 |  77 ++++++
 .../Componentbuilder/Search/Type/Basic.php    | 127 +++++++++
 .../Componentbuilder/Search/Type/Regex.php    | 112 ++++++++
 .../Componentbuilder/Search/Type/index.html   |   1 +
 22 files changed, 845 insertions(+), 91 deletions(-)
 create mode 100644 libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/SearchInterface.php
 create mode 100644 libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/SearchTypeInterface.php
 create mode 100644 libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/Basic.php
 create mode 100644 libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/Regex.php
 create mode 100644 libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/index.html

diff --git a/README.md b/README.md
index 20ac6437d..342c18d3f 100644
--- a/README.md
+++ b/README.md
@@ -140,14 +140,14 @@ TODO
 + *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io)
 + *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder)
 + *First Build*: 30th April, 2015
-+ *Last Build*: 14th September, 2022
++ *Last Build*: 16th September, 2022
 + *Version*: 3.1.5
 + *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved.
 + *License*: GNU General Public License version 2 or later; see LICENSE.txt
-+ *Line count*: **330282**
++ *Line count*: **331035**
 + *Field count*: **2002**
-+ *File count*: **2161**
-+ *Folder count*: **374**
++ *File count*: **2166**
++ *Folder count*: **375**
 
 > This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](http://joomlacomponentbuilder.com).
 > Developed by [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com)
diff --git a/admin/README.txt b/admin/README.txt
index 20ac6437d..342c18d3f 100644
--- a/admin/README.txt
+++ b/admin/README.txt
@@ -140,14 +140,14 @@ TODO
 + *Author*: [Llewellyn van der Merwe](mailto:joomla@vdm.io)
 + *Name*: [Component Builder](https://git.vdm.dev/joomla/Component-Builder)
 + *First Build*: 30th April, 2015
-+ *Last Build*: 14th September, 2022
++ *Last Build*: 16th September, 2022
 + *Version*: 3.1.5
 + *Copyright*: Copyright (C) 2015 Vast Development Method. All rights reserved.
 + *License*: GNU General Public License version 2 or later; see LICENSE.txt
-+ *Line count*: **330282**
++ *Line count*: **331035**
 + *Field count*: **2002**
-+ *File count*: **2161**
-+ *Folder count*: **374**
++ *File count*: **2166**
++ *Folder count*: **375**
 
 > This **component** was build with a [Joomla](https://extensions.joomla.org/extension/component-builder/) [Automated Component Builder](http://joomlacomponentbuilder.com).
 > Developed by [Llewellyn van der Merwe](mailto:llewellyn@joomlacomponentbuilder.com)
diff --git a/admin/language/en-GB/en-GB.com_componentbuilder.ini b/admin/language/en-GB/en-GB.com_componentbuilder.ini
index 5d19974ee..8fb1a0828 100644
--- a/admin/language/en-GB/en-GB.com_componentbuilder.ini
+++ b/admin/language/en-GB/en-GB.com_componentbuilder.ini
@@ -7760,7 +7760,6 @@ COM_COMPONENTBUILDER_MODEL_AFTER_MODELLING="Model (after modelling)"
 COM_COMPONENTBUILDER_MODEL_BEFORE_MODELLING="Model (before modelling)"
 COM_COMPONENTBUILDER_MODULE="Module"
 COM_COMPONENTBUILDER_MODULES="Modules"
-COM_COMPONENTBUILDER_MORE_SOON="More soon"
 COM_COMPONENTBUILDER_MOVE="Move"
 COM_COMPONENTBUILDER_NAME="Name"
 COM_COMPONENTBUILDER_NAME_ASC="Name (Asc)"
diff --git a/admin/models/ajax.php b/admin/models/ajax.php
index 9c3ce9a3e..b347bafa8 100644
--- a/admin/models/ajax.php
+++ b/admin/models/ajax.php
@@ -3622,17 +3622,17 @@ class ComponentbuilderModelAjax extends ListModel
 		int $matchCase, int $wholeWord, int $regexSearch, int $componentId): ?array
 	{
 		// check if this is a valid table
-		if (SearchFactory('Table')->exist($tableName))
+		if (SearchFactory::_('Table')->exist($tableName))
 		{
 			// load the configurations
-			SearchFactory('Config')->table_name = $tableName;
-			SearchFactory('Config')->search_value = $searchValue;
-			SearchFactory('Config')->match_case = $matchCase;
-			SearchFactory('Config')->whole_word = $wholeWord;
-			SearchFactory('Config')->regex_search = $regexSearch;
-			SearchFactory('Config')->component_id = $componentId;
+			SearchFactory::_('Config')->table_name = $tableName;
+			SearchFactory::_('Config')->search_value = $searchValue;
+			SearchFactory::_('Config')->match_case = $matchCase;
+			SearchFactory::_('Config')->whole_word = $wholeWord;
+			SearchFactory::_('Config')->regex_search = $regexSearch;
+			SearchFactory::_('Config')->component_id = $componentId;
 
-			if (($items = SearchFactory('Agent')->find()) !== null)
+			if (($items = SearchFactory::_('Agent')->find()) !== null)
 			{
 				return ['success' => JText::sprintf('COM_COMPONENTBUILDER_WE_FOUND_SOME_INSTANCES_IN_S', $tableName), 'items' => $items];
 			}
diff --git a/admin/views/search/tmpl/default.php b/admin/views/search/tmpl/default.php
index d28ecae59..5413d57c0 100644
--- a/admin/views/search/tmpl/default.php
+++ b/admin/views/search/tmpl/default.php
@@ -16,6 +16,7 @@ JHtml::addIncludePath(JPATH_COMPONENT.'/helpers/html');
 JHtml::_('behavior.formvalidator');
 JHtml::_('formbehavior.chosen', 'select');
 JHtml::_('behavior.keepalive');
+use VDM\Joomla\Componentbuilder\Search\Factory as SearchFactory;
 ?>
 <?php if ($this->canDo->get('search.access')): ?>
 <script type="text/javascript">
@@ -41,7 +42,29 @@ JHtml::_('behavior.keepalive');
 <?php else : ?>
 <div id="j-main-container">
 <?php endif; ?>
-	<?php echo JText::_('COM_COMPONENTBUILDER_MORE_SOON'); ?>
+	<?php
+	// lets do some tests with the API
+	$tableName = 'admin_view';
+	$searchValue = ' array(';
+	// set the search configurations
+	SearchFactory::_('Config')->table_name = $tableName;
+	SearchFactory::_('Config')->search_value = $searchValue;
+	SearchFactory::_('Config')->match_case = 0;
+	SearchFactory::_('Config')->whole_word = 0;
+	SearchFactory::_('Config')->regex_search = 0;
+	SearchFactory::_('Config')->component_id = 0;
+
+	if (($items = SearchFactory::_('Agent')->find()) !== null)
+	{
+		echo JText::sprintf('COM_COMPONENTBUILDER_WE_FOUND_SOME_INSTANCES_IN_S', $tableName) . '<br /><pre>';
+		var_dump($items);
+		echo '</pre>';
+	}
+	else
+	{
+		echo JText::sprintf('COM_COMPONENTBUILDER_NO_INSTANCES_WHERE_FOUND_S', $tableName);
+	}
+ 	?>
 </div>
 <input type="hidden" name="task" value="" />
 <?php echo JHtml::_('form.token'); ?>
diff --git a/componentbuilder.xml b/componentbuilder.xml
index 522cc8fa3..112cdbfe8 100644
--- a/componentbuilder.xml
+++ b/componentbuilder.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <extension type="component" version="4" method="upgrade">
 	<name>COM_COMPONENTBUILDER</name>
-	<creationDate>14th September, 2022</creationDate>
+	<creationDate>16th September, 2022</creationDate>
 	<author>Llewellyn van der Merwe</author>
 	<authorEmail>joomla@vdm.io</authorEmail>
 	<authorUrl>https://dev.vdm.io</authorUrl>
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent.php
index 34a5b8c5b..1708f1046 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent.php
@@ -125,7 +125,7 @@ class Agent
 			$set++;
 		}
 
-		return $this->search->found($table);
+		return $this->search->get($table);
 	}
 
 	/**
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Replace.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Replace.php
index c0de189bf..f96de3d4d 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Replace.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Replace.php
@@ -117,7 +117,7 @@ class Replace implements ReplaceInterface
 		{
 			foreach ($item as $field => $value)
 			{
-				if ($field !== 'id' && ($_value = $this->update->value($value, $id, $field, $table)) !== null)
+				if ($field !== 'id' && ($_value = $this->update->value($value)) !== null)
 				{
 					if (empty($this->updated[$table][$id]))
 					{
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Search.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Search.php
index 3aac163b5..4c0adb634 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Search.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Search.php
@@ -12,9 +12,11 @@
 namespace VDM\Joomla\Componentbuilder\Search\Agent;
 
 
+use VDM\Joomla\Utilities\ArrayHelper;
+use VDM\Joomla\Utilities\StringHelper;
 use VDM\Joomla\Componentbuilder\Search\Factory;
-use VDM\Joomla\Componentbuilder\Search\Config;
-use VDM\Joomla\Componentbuilder\Search\Table;
+use VDM\Joomla\Componentbuilder\Search\Interfaces\SearchTypeInterface as SearchEngine;
+use VDM\Joomla\Componentbuilder\Search\Interfaces\SearchInterface;
 
 
 /**
@@ -22,52 +24,265 @@ use VDM\Joomla\Componentbuilder\Search\Table;
  * 
  * @since 3.2.0
  */
-class Search
+class Search implements SearchInterface
 {
 	/**
-	 * Search Config
+	 * Search results found
 	 *
-	 * @var    Config
+	 * @var    array
 	 * @since 3.2.0
 	 */
-	protected Config $config;
+	protected array $found = [];
 
 	/**
-	 * Table
+	 * Search Engine
 	 *
-	 * @var    Table
+	 * @var    SearchEngine
 	 * @since 3.2.0
 	 */
-	protected Table $table;
+	protected SearchEngine $search;
 
 	/**
 	 * Constructor
 	 *
-	 * @param Config|null           $config           The search config object.
-	 * @param Table|null             $table            The search table object.
+	 * @param SearchEngine|null      $search    The search engine object.
 	 *
 	 * @since 3.2.0
 	 */
-	public function __construct(?Config $config = null, ?Table $table = null)
+	public function __construct(?SearchEngine $search = null)
 	{
-		$this->config = $config ?: Factory::_('Config');
-		$this->table = $table ?: Factory::_('Table');
+		$this->search = $search ?: Factory::_('Search');
+	}
+
+	/**
+	 * Get found values
+	 *
+	 * @param string     $table   The table being searched
+	 *
+	 * @return  array|null
+	 * @since 3.2.0
+	 */
+	public function get(string $table): ?array
+	{
+		if (isset($this->found[$table]))
+		{
+			return $this->found[$table];
+		}
+
+		return null;
 	}
 
 	/**
 	 * Search inside a value
 	 *
 	 * @param   mixed         $value     The field value
-	 * @param   int               $id          The item ID
-	 * @param   string          $field      The field key
-	 * @param   string|null    $table     The table
+	 * @param   int           $id        The item ID
+	 * @param   string        $field     The field key
+	 * @param   string        $table     The table
 	 *
 	 * @return  bool
 	 * @since 3.2.0
 	 */
-	public function value($value, int $id, string $field, ?string $table = null): bool
+	public function value($value, int $id, string $field, string $table): bool
 	{
-		return true;
+		// search the mixed value
+		$found = $this->searchValue($value);
+
+		// check if we found any match
+		if (ArrayHelper::check($found))
+		{
+			foreach ($found as $line => $line_value)
+			{
+				// may not be needed... but being old school
+				$this->prep($id, $field, $table);
+
+				// load the detail into our multidimensional array... lol
+				// Table->Item_id->Field_name->Line_number = marked_full_line
+				// Search Example: soon...
+				// Marked Line Example: Soon....
+				$this->found[$table][$id][$field][$line] = $line_value;
+			}
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Empty the found values
+	 *
+	 * @param string   $table   The table being searched
+	 *
+	 * @return  void
+	 * @since 3.2.0
+	 */
+	public function reset(string $table)
+	{
+		unset($this->found[$table]);
+	}
+
+	/**
+	 * Search inside a string
+	 *
+	 * @param   mixed    $value    The field value
+	 *
+	 * @return  array|null
+	 * @since 3.2.0
+	 */
+	protected function searchValue($value): ?array
+	{
+		// check if this is an array
+		$found = null;
+
+		// I know this is a little crazy... TODO refactor into recursion functions
+		// the possibility of searching sub-forms in sub-forms
+		if (ArrayHelper::check($value))
+		{
+			// first layer
+			foreach ($value as $keys => $rows)
+			{
+				if (ArrayHelper::check($rows))
+				{
+					// second layer
+					foreach ($rows as $key => $row)
+					{
+						if (ArrayHelper::check($row))
+						{
+							// third layer
+							foreach ($row as $ke => $ro)
+							{
+								if (ArrayHelper::check($ro))
+								{
+									// forth layer
+									foreach ($ro as $k => $r)
+									{
+										if (StringHelper::check($r))
+										{
+											if (($_found = $this->string($r)) !== null)
+											{
+												foreach ($_found as $_n => $_f)
+												{
+													$found[$keys . '.' . $key . '.' . $ke . '.' . $k . '.' . $_n] = $_f;
+												}
+											}
+										}
+									}
+								}
+								elseif (StringHelper::check($ro))
+								{
+									if (($_found = $this->string($ro)) !== null)
+									{
+										foreach ($_found as $_n => $_f)
+										{
+											$found[$keys. '.' . $key . '.' . $ke . '.' . $_n] = $_f;
+										}
+									}
+								}
+
+							}
+						}
+						elseif (StringHelper::check($row))
+						{
+							if (($_found = $this->string($row)) !== null)
+							{
+								foreach ($_found as $_n => $_f)
+								{
+									$found[$keys. '.' . $key . '.' . $_n] = $_f;
+								}
+							}
+						}
+					}
+				}
+				elseif (StringHelper::check($rows))
+				{
+					if (($_found = $this->string($rows)) !== null)
+					{
+						foreach ($_found as $_n => $_f)
+						{
+							$found[$keys. '.' . $_n] = $_f;
+						}
+					}
+				}
+			}
+		}
+		elseif (StringHelper::check($value))
+		{
+			$found = $this->string($value);
+		}
+
+		return $found;
+	}
+
+	/**
+	 * Search inside a string
+	 *
+	 * @param   string   $value     The field value
+	 *
+	 * @return  array|null
+	 * @since 3.2.0
+	 */
+	protected function string(string $value): ?array
+	{
+		// line counter
+		$line = 1;
+
+		// check if string has a new line
+		if (\preg_match('/\R/', $value))
+		{
+			$search_array = \preg_split('/\R/', $value);
+
+			// start search bucket
+			$found = [];
+
+			// loop over the lines
+			foreach ($search_array as $line_value)
+			{
+				if (($_found = $this->search->string($line_value)) !== null)
+				{
+					$found[$line] = $_found;
+				}
+
+				// next line
+				$line++;
+			}
+
+			if (ArrayHelper::check($found))
+			{
+				return $found;
+			}
+		}
+		elseif (($found = $this->search->string($value)) !== null)
+		{
+			return [$line => $found];
+		}
+
+		return null;
+	}
+
+	/**
+	 * Prep the bucket
+	 *
+	 * @param   int        $id       The item ID
+	 * @param   string     $field    The field key
+	 * @param   string     $table    The table
+	 *
+	 * @return  void
+	 * @since 3.2.0
+	 */
+	protected function prep(int $id, string $field, string $table)
+	{
+		if (empty($this->found[$table]))
+		{
+			$this->found[$table] = [];
+		}
+		if (empty($this->found[$table][$id]))
+		{
+			$this->found[$table][$id] = [];
+		}
+		if (empty($this->found[$table][$id][$field]))
+		{
+			$this->found[$table][$id][$field] = [];
+		}
 	}
 
 }
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Update.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Update.php
index b253e4bbd..635593ac0 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Update.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Agent/Update.php
@@ -12,9 +12,10 @@
 namespace VDM\Joomla\Componentbuilder\Search\Agent;
 
 
+use VDM\Joomla\Utilities\ArrayHelper;
+use VDM\Joomla\Utilities\StringHelper;
 use VDM\Joomla\Componentbuilder\Search\Factory;
-use VDM\Joomla\Componentbuilder\Search\Config;
-use VDM\Joomla\Componentbuilder\Search\Table;
+use VDM\Joomla\Componentbuilder\Search\Interfaces\SearchTypeInterface as SearchEngine;
 
 
 /**
@@ -25,49 +26,113 @@ use VDM\Joomla\Componentbuilder\Search\Table;
 class Update
 {
 	/**
-	 * Search Config
+	 * Search Engine
 	 *
-	 * @var    Config
+	 * @var    SearchEngine
 	 * @since 3.2.0
 	 */
-	protected Config $config;
-
-	/**
-	 * Table
-	 *
-	 * @var    Table
-	 * @since 3.2.0
-	 */
-	protected Table $table;
+	protected SearchEngine $search;
 
 	/**
 	 * Constructor
 	 *
-	 * @param Config|null           $config           The search config object.
-	 * @param Table|null             $table            The search table object.
+	 * @param SearchEngine|null    $search    The search engine object.
 	 *
 	 * @since 3.2.0
 	 */
-	public function __construct(?Config $config = null, ?Table $table = null)
+	public function __construct(?SearchEngine $search = null)
 	{
-		$this->config = $config ?: Factory::_('Config');
-		$this->table = $table ?: Factory::_('Table');
+		$this->search = $search ?: Factory::_('Search');
 	}
 
 	/**
-	 * Update value
+	 * Update the value
 	 *
-	 * @param   mixed         $value     The field value
-	 * @param   int               $id          The item ID
-	 * @param   string          $field      The field key
-	 * @param   string|null    $table     The table
+	 * @param   mixed    $value    The field value
+	 * @param   int      $line     The line to update  (0 = all)
 	 *
 	 * @return  mixed
 	 * @since 3.2.0
 	 */
-	public function value($value, int $id, string $field, ?string $table = null)
+	public function value($value, int $line = 0)
 	{
-		return $value;
+		// update the value
+		$update = $this->updateValue($value, $line);
+
+		// was anything updated
+		if ($value === $update)
+		{
+			return null;
+		}
+
+		return $update;
+	}
+
+	/**
+	 * Update all search-replace instances inside a value
+	 *
+	 * @param   mixed    $value   The field value
+	 * @param   int      $line    The line to update  (0 = all)
+	 *
+	 * @return  mixed
+	 * @since 3.2.0
+	 */
+	protected function updateValue($value, int $line = 0)
+	{
+		if (ArrayHelper::check($value))
+		{
+			echo '<pre>'; var_dump($value); exit;
+		}
+		elseif (StringHelper::check($value))
+		{
+			return $this->string($value, $line);
+		}
+		else
+		{
+			// this should not happen
+			echo '<pre>Error:<br />'; var_dump($value); exit;
+		}
+	}
+
+	/**
+	 * Update all search-replace instances inside a string
+	 *
+	 * @param   string    $value   The field value
+	 * @param   int       $line    The line to update  (0 = all)
+	 *
+	 * @return  string
+	 * @since 3.2.0
+	 */
+	protected function string(string $value, int $line = 0): string
+	{
+		// check if string has a new line
+		if (\preg_match('/\R/', $value) && $line > 0)
+		{
+			// line counter
+			$line_number = 1;
+
+			$search_array = \preg_split('/\R/', $value);
+
+			// loop over the lines
+			foreach ($search_array as $nr => $line_value)
+			{
+				if ($line_number == $line)
+				{
+					$search_array[$nr] = $this->search->replace($line_value);
+
+					// since we are targeting on line (and possibly one number)
+					// this can only happen once, and so we return at this point
+					return implode(PHP_EOL, $search_array);
+				}
+				// next line
+				$line_number++;
+			}
+
+			// no update took place so we just return the original value
+			return $value;
+		}
+
+		return $this->search->replace($value);
 	}
 
 }
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Config.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Config.php
index 83e423980..a3a0eb8a8 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Config.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Config.php
@@ -25,10 +25,10 @@ class Config extends BaseConfig
 	/**
 	 * get posted search value
 	 *
-	 * @return  string  Raw search value
+	 * @return  string|null  Raw search value
 	 * @since 3.2.0
 	 */
-	protected function getSearchvalue(): string
+	protected function getSearchvalue(): ?string
 	{
 		return $this->input->post->get('search_value', null, 'RAW');
 	}
@@ -36,10 +36,10 @@ class Config extends BaseConfig
 	/**
 	 * get posted replace value
 	 *
-	 * @return  string  Raw replace value
+	 * @return  string|null  Raw replace value
 	 * @since 3.2.0
 	 */
-	protected function getReplacevalue(): string
+	protected function getReplacevalue(): ?string
 	{
 		return $this->input->post->get('replace_value', null, 'RAW');
 	}
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/FindInterface.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/FindInterface.php
index d8bca4d6b..a1a8a1fc2 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/FindInterface.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/FindInterface.php
@@ -60,6 +60,7 @@ interface FindInterface
 	 * @return  void
 	 * @since 3.2.0
 	 */
-	public function reset(?string $table = null);
+	public function reset(?string $table = null);
+
 }
 
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/ModelInterface.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/ModelInterface.php
index c0aa6a2a2..e104b7f31 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/ModelInterface.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/ModelInterface.php
@@ -34,15 +34,15 @@ interface ModelInterface
 
 	/**
 	 * Model the values of an item
-	 *          Example: $this->item('table_name', Object);
+	 *          Example: $this->item(Object, 'table_name');
 	 *
-	 * @param   string        $table     The table
-	 * @param   object       $item      The item object
+	 * @param   object         $item      The item object
+	 * @param   string|null    $table     The table
 	 *
-	 * @return  object
+	 * @return  object|null
 	 * @since 3.2.0
 	 */
-	public function item(object $item, ?string $table = null): object;
+	public function item(object $item, ?string $table = null): ?object;
 
 	/**
 	 * Model the values of multiple items
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/SearchInterface.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/SearchInterface.php
new file mode 100644
index 000000000..25a1a17bc
--- /dev/null
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/SearchInterface.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * @package    Joomla.Component.Builder
+ *
+ * @created    30th April, 2015
+ * @author     Llewellyn van der Merwe <https://dev.vdm.io>
+ * @git        Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
+ * @copyright  Copyright (C) 2015 Vast Development Method. All rights reserved.
+ * @license    GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+namespace VDM\Joomla\Componentbuilder\Search\Interfaces;
+
+
+/**
+ * Search Interface
+ * 
+ * @since 3.2.0
+ */
+interface SearchInterface
+{
+	/**
+	 * Get found values
+	 *
+	 * @param string     $table   The table being searched
+	 *
+	 * @return  array|null
+	 * @since 3.2.0
+	 */
+	public function get(string $table): ?array;
+
+	/**
+	 * Search inside a value
+	 *
+	 * @param   mixed         $value     The field value
+	 * @param   int               $id          The item ID
+	 * @param   string          $field      The field key
+	 * @param   string          $table     The table
+	 *
+	 * @return  bool
+	 * @since 3.2.0
+	 */
+	public function value($value, int $id, string $field, string $table): bool;
+
+	/**
+	 * Empty the found values
+	 *
+	 * @param string     $table   The table being searched
+	 *
+	 * @return  void
+	 * @since 3.2.0
+	 */
+	public function reset(string $table);
+
+}
+
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/SearchTypeInterface.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/SearchTypeInterface.php
new file mode 100644
index 000000000..9f3408b8e
--- /dev/null
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Interfaces/SearchTypeInterface.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @package    Joomla.Component.Builder
+ *
+ * @created    30th April, 2015
+ * @author     Llewellyn van der Merwe <https://dev.vdm.io>
+ * @git        Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
+ * @copyright  Copyright (C) 2015 Vast Development Method. All rights reserved.
+ * @license    GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+namespace VDM\Joomla\Componentbuilder\Search\Interfaces;
+
+
+/**
+ * Search Type Interface
+ * 
+ * @since 3.2.0
+ */
+interface SearchTypeInterface
+{
+	/**
+	 * Search inside a string
+	 *
+	 * @param   string    $value   The string value
+	 *
+	 * @return  string|null    The marked string if found, else null
+	 * @since 3.2.0
+	 */
+	public function string(string $value): ?string;
+
+	/**
+	 * Replace found instances inside string value
+	 *
+	 * @param   string     $value      The string value to update
+	 *
+	 * @return  string      The updated string
+	 * @since 3.2.0
+	 */
+	public function replace(string $value): string;
+
+}
+
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Model.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Model.php
index 7e5cc2984..83b0f5f40 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Model.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Model.php
@@ -12,10 +12,11 @@
 namespace VDM\Joomla\Componentbuilder\Search;
 
 
+use VDM\Joomla\Utilities\StringHelper;
+use VDM\Joomla\Utilities\ArrayHelper;
 use VDM\Joomla\Componentbuilder\Search\Factory;
 use VDM\Joomla\Componentbuilder\Search\Config;
 use VDM\Joomla\Componentbuilder\Search\Table;
-use VDM\Joomla\Utilities\ArrayHelper;
 
 
 /**
@@ -65,15 +66,15 @@ abstract class Model
 
 	/**
 	 * Model the values of an item
-	 *          Example: $this->item(Object, 'table_name');
+	 *          Example: $this->item('table_name', Object);
 	 *
-	 * @param   object          $item      The item object
+	 * @param   object         $item      The item object
 	 * @param   string|null    $table     The table
 	 *
-	 * @return  object
+	 * @return  object|null
 	 * @since 3.2.0
 	 */
-	public function item(object $item, ?string $table = null): object
+	public function item(object $item, ?string $table = null): ?object
 	{
 		// set the table name
 		if (empty($table))
@@ -81,19 +82,39 @@ abstract class Model
 			$table = $this->config->table_name;
 		}
 
+		// field counter
+		$field_number = 0;
+
 		// check if this is a valid table
 		if (($fields = $this->table->fields($table)) !== null)
 		{
 			foreach ($fields as $field)
 			{
+				// model a value if it exists
 				if(isset($item->{$field}))
 				{
 					$item->{$field} = $this->value($item->{$field}, $field, $table);
+
+					// remove empty values
+					if (!StringHelper::check($item->{$field}) && !ArrayHelper::check($item->{$field}, true))
+					{
+						unset($item->{$field});
+					}
+					else
+					{
+						$field_number++;
+					}
 				}
 			}
 		}
 
-		return $item;
+		// all items must have more than one field or its empty (1 = id)
+		if ($field_number > 1)
+		{
+			return $item;
+		}
+
+		return null;
 	}
 
 	/**
@@ -120,14 +141,24 @@ abstract class Model
 			foreach ($items as $id => &$item)
 			{
 				// model the item
-				$item = $this->item($item, $table);
+				if (($item = $this->item($item, $table)) !== null)
+				{
+					// add the last ID
+					$this->last[$table] = $item->id;
+				}
+				else
+				{
+					unset($items[$id]);
+				}
+			}
 
-				// add the last ID
-				$this->last[$table] = $item->id;
+			if (ArrayHelper::check($items))
+			{
+				return $items;
 			}
 		}
 
-		return $items;
+		return null;
 	}
 
 	/**
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Model/Get.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Model/Get.php
index 4f5b3d756..de3e80407 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Model/Get.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Model/Get.php
@@ -12,6 +12,8 @@
 namespace VDM\Joomla\Componentbuilder\Search\Model;
 
 
+use VDM\Joomla\Utilities\JsonHelper;
+use VDM\Joomla\Utilities\StringHelper;
 use VDM\Joomla\Componentbuilder\Search\Interfaces\ModelInterface;
 use VDM\Joomla\Componentbuilder\Search\Model;
 
@@ -43,7 +45,7 @@ class Get extends Model implements ModelInterface
 		}
 
 		// check if this is a valid table
-		if (($store = $this->table->get($table, $field, 'store')) !== null)
+		if (StringHelper::check($value) && ($store = $this->table->get($table, $field, 'store')) !== null)
 		{
 			// open the value based on the store method
 			switch($store)
@@ -52,7 +54,11 @@ class Get extends Model implements ModelInterface
 					$value = \base64_decode($value);
 				break;
 				case 'json':
-					$value = \json_decode($value, true);
+					// check if there is a json string
+					if (JsonHelper::check($value))
+					{
+						$value = \json_decode($value, true);
+					}
 				break;
 			}
 		}
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Service/Agent.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Service/Agent.php
index d487ab809..41f8966d4 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Service/Agent.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Service/Agent.php
@@ -117,8 +117,7 @@ class Agent implements ServiceProviderInterface
 	public function getSearch(Container $container): Search
 	{
 		return new Search(
-			$container->get('Config'),
-			$container->get('Table')
+			$container->get('Search')
 		);
 	}
 
@@ -133,8 +132,7 @@ class Agent implements ServiceProviderInterface
 	public function getUpdate(Container $container): Update
 	{
 		return new Update(
-			$container->get('Config'),
-			$container->get('Table')
+			$container->get('Search')
 		);
 	}
 
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Service/Search.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Service/Search.php
index 6b26bf9aa..3eac97b83 100644
--- a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Service/Search.php
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Service/Search.php
@@ -16,6 +16,9 @@ use Joomla\DI\Container;
 use Joomla\DI\ServiceProviderInterface;
 use VDM\Joomla\Componentbuilder\Search\Config;
 use VDM\Joomla\Componentbuilder\Search\Table;
+use VDM\Joomla\Componentbuilder\Search\Interfaces\SearchTypeInterface as SearchEngine;
+use VDM\Joomla\Componentbuilder\Search\Type\Regex;
+use VDM\Joomla\Componentbuilder\Search\Type\Basic;
 
 
 /**
@@ -25,6 +28,14 @@ use VDM\Joomla\Componentbuilder\Search\Table;
  */
 class Search implements ServiceProviderInterface
 {
+	/**
+	 * Selected search engine
+	 *
+	 * @var     int
+	 * @since 3.2.0
+	 **/
+	protected $searchEngine = 101;
+
 	/**
 	 * Registers the service provider with a DI container.
 	 *
@@ -40,6 +51,15 @@ class Search implements ServiceProviderInterface
 
 		$container->alias(Table::class, 'Table')
 			->share('Table', [$this, 'getTable'], true);
+
+		$container->alias(Regex::class, 'Search.Regex')
+			->share('Search.Regex', [$this, 'getRegex'], true);
+
+		$container->alias(Basic::class, 'Search.Basic')
+			->share('Search.Basic', [$this, 'getBasic'], true);
+
+		$container->alias(SearchEngine::class, 'Search')
+			->share('Search', [$this, 'getSearch'], true);
 	}
 
 	/**
@@ -69,6 +89,63 @@ class Search implements ServiceProviderInterface
 			$container->get('Config')
 		);
 	}
+
+	/**
+	 * Get the Regex Type Search Engine
+	 *
+	 * @param   Container  $container  The DI container.
+	 *
+	 * @return  Regex
+	 * @since 3.2.0
+	 */
+	public function getRegex(Container $container): Regex
+	{
+		return new Regex(
+			$container->get('Config')
+		);
+	}
+
+	/**
+	 * Get the Basic Type Search Engine
+	 *
+	 * @param   Container  $container  The DI container.
+	 *
+	 * @return  Basic
+	 * @since 3.2.0
+	 */
+	public function getBasic(Container $container): Basic
+	{
+		return new Basic(
+			$container->get('Config')
+		);
+	}
+
+	/**
+	 * Get the Search Engine
+	 *
+	 * @param   Container  $container  The DI container.
+	 *
+	 * @return  SearchEngine
+	 * @since 3.2.0
+	 */
+	public function getSearch(Container $container): SearchEngine
+	{
+		// set the search engine to use for this container
+		if ($this->searchEngine == 101)
+		{
+			$this->searchEngine = (int) $container->get('Config')->regex_search;
+		}
+
+		// get the correct type of search engine
+		if ($this->searchEngine ==  1)
+		{
+			return $container->get('Search.Regex');
+		}
+
+		// the default is the basic
+		return $container->get('Search.Basic');
+	}
+
 
 }
 
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/Basic.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/Basic.php
new file mode 100644
index 000000000..7f7d991a2
--- /dev/null
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/Basic.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * @package    Joomla.Component.Builder
+ *
+ * @created    30th April, 2015
+ * @author     Llewellyn van der Merwe <https://dev.vdm.io>
+ * @git        Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
+ * @copyright  Copyright (C) 2015 Vast Development Method. All rights reserved.
+ * @license    GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+namespace VDM\Joomla\Componentbuilder\Search\Type;
+
+
+use VDM\Joomla\Componentbuilder\Search\Factory;
+use VDM\Joomla\Componentbuilder\Search\Config;
+use VDM\Joomla\Utilities\StringHelper;
+use VDM\Joomla\Componentbuilder\Search\Interfaces\SearchTypeInterface;
+
+
+/**
+ * Search Type String
+ * 
+ * @since 3.2.0
+ */
+class Basic implements SearchTypeInterface
+{
+	/**
+	 * Search Config
+	 *
+	 * @var    Config
+	 * @since 3.2.0
+	 */
+	protected Config $config;
+
+	/**
+	 * Search Value
+	 *
+	 * @var    string|null
+	 * @since 3.2.0
+	 */
+	protected ?string $searchValue;
+
+	/**
+	 * Replace Value
+	 *
+	 * @var    string|null
+	 * @since 3.2.0
+	 */
+	protected ?string $replaceValue;
+
+	/**
+	 * Search Should Match Case
+	 *
+	 * @var    int
+	 * @since 3.2.0
+	 */
+	protected int $matchCase = 0;
+
+	/**
+	 * Search Should Match Whole Word
+	 *
+	 * @var    int
+	 * @since 3.2.0
+	 */
+	protected int $wholeWord = 0;
+
+	/**
+	 * Constructor
+	 *
+	 * @param Config|null           $config           The search config object.
+	 *
+	 * @since 3.2.0
+	 */
+	public function __construct(?Config $config = null)
+	{
+		$this->config = $config ?: Factory::_('Config');
+
+		// set some class values
+		$this->searchValue = $this->config->search_value;
+		$this->replaceValue = $this->config->replace_value; // TODO
+		$this->matchCase = $this->config->match_case;
+		$this->wholeWord = $this->config->whole_word; // TODO
+	}
+
+	/**
+	 * Search inside a string
+	 *
+	 * @param   string    $value   The string value
+	 *
+	 * @return  string|null    The marked string if found, else null
+	 * @since 3.2.0
+	 */
+	public function string(string $value): ?string
+	{
+		if (StringHelper::check($this->searchValue))
+		{
+			if ($this->matchCase == 1)
+			{
+				if (strpos($value, $this->searchValue) !== false)
+				{
+					return trim(str_replace($this->searchValue, '{+' . '|' . '=[' . $this->searchValue . ']=' . '|' . '+}', $value));
+				}
+			}
+			elseif (stripos($value, $this->searchValue) !== false)
+			{
+				return trim(str_ireplace($this->searchValue, '{+' . '|' . '=[' . $this->searchValue . ']=' . '|' . '+}', $value));
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Replace found instances inside string value
+	 *
+	 * @param   string     $value      The string value to update
+	 *
+	 * @return  string      The updated string
+	 * @since 3.2.0
+	 */
+	public function replace(string $value): string
+	{
+		return $value;
+	}
+
+}
+
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/Regex.php b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/Regex.php
new file mode 100644
index 000000000..4ee4e23eb
--- /dev/null
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/Regex.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * @package    Joomla.Component.Builder
+ *
+ * @created    30th April, 2015
+ * @author     Llewellyn van der Merwe <https://dev.vdm.io>
+ * @git        Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
+ * @copyright  Copyright (C) 2015 Vast Development Method. All rights reserved.
+ * @license    GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+namespace VDM\Joomla\Componentbuilder\Search\Type;
+
+
+use VDM\Joomla\Componentbuilder\Search\Factory;
+use VDM\Joomla\Componentbuilder\Search\Config;
+use VDM\Joomla\Componentbuilder\Search\Interfaces\SearchTypeInterface;
+
+
+/**
+ * Search Type Regex
+ * 
+ * @since 3.2.0
+ */
+class Regex implements SearchTypeInterface
+{
+	/**
+	 * Search Config
+	 *
+	 * @var    Config
+	 * @since 3.2.0
+	 */
+	protected Config $config;
+
+	/**
+	 * Search Value
+	 *
+	 * @var    string
+	 * @since 3.2.0
+	 */
+	protected string $searchValue;
+
+	/**
+	 * Replace Value
+	 *
+	 * @var    string
+	 * @since 3.2.0
+	 */
+	protected string $replaceValue;
+
+	/**
+	 * Search Should Match Case
+	 *
+	 * @var    int
+	 * @since 3.2.0
+	 */
+	protected int $matchCase = 0;
+
+	/**
+	 * Search Should Match Whole Word
+	 *
+	 * @var    int
+	 * @since 3.2.0
+	 */
+	protected int $wholeWord = 0;
+
+	/**
+	 * Constructor
+	 *
+	 * @param Config|null           $config           The search config object.
+	 *
+	 * @since 3.2.0
+	 */
+	public function __construct(?Config $config = null)
+	{
+		$this->config = $config ?: Factory::_('Config');
+
+		// set some class values
+		$this->searchValue = $this->config->search_value;
+		$this->replaceValue = $this->config->replace_value; // TODO
+		$this->matchCase = $this->config->match_case;
+		$this->wholeWord = $this->config->whole_word; // TODO
+	}
+
+	/**
+	 * Search inside a string
+	 *
+	 * @param   string    $value   The string value
+	 *
+	 * @return  string|null    The marked string if found, else null
+	 * @since 3.2.0
+	 */
+	public function string(string $value): ?string
+	{
+		return null;
+	}
+
+	/**
+	 * Replace found instances inside string value
+	 *
+	 * @param   string     $value      The string value to update
+	 *
+	 * @return  string      The updated string
+	 * @since 3.2.0
+	 */
+	public function replace(string $value): string
+	{
+		return $value;
+	}
+
+}
+
diff --git a/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/index.html b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/index.html
new file mode 100644
index 000000000..fa6d84e80
--- /dev/null
+++ b/libraries/jcb_powers/VDM.Joomla/src/Componentbuilder/Search/Type/index.html
@@ -0,0 +1 @@
+<html><body bgcolor="#FFFFFF"></body></html>
\ No newline at end of file