From 08f20e51c6a77a6f7998bbdac23bebe0ee03a125 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Roland=20H=C3=A4der?= <roland@mxchange.org>
Date: Fri, 22 Feb 2013 03:20:56 +0000
Subject: [PATCH] Fixed criteria handling

---
 .../extended/class_LocalSearchCriteria.php    |  3 +-
 .../main/class_BaseFrameworkSystem.php        |  2 +-
 .../main/criteria/class_BaseCriteria.php      |  6 +-
 .../criteria/search/class_SearchCriteria.php  | 69 +++++++++++--
 .../databases/class_LocalFileDatabase.php     | 98 ++++++++++---------
 .../factories/objects/class_ObjectFactory.php |  4 +-
 6 files changed, 122 insertions(+), 60 deletions(-)

diff --git a/inc/classes/interfaces/criteria/extended/class_LocalSearchCriteria.php b/inc/classes/interfaces/criteria/extended/class_LocalSearchCriteria.php
index 32ccdcf7..58606803 100644
--- a/inc/classes/interfaces/criteria/extended/class_LocalSearchCriteria.php
+++ b/inc/classes/interfaces/criteria/extended/class_LocalSearchCriteria.php
@@ -68,9 +68,10 @@ interface LocalSearchCriteria extends Criteria {
 	 *
 	 * @param	$key			Key element to check
 	 * @param	$value			Value to check
+	 * @param	$separator		Separator for "exploding" $value (default: ',')
 	 * @return	$isMatching		Whether the key/value is matching or excluded
 	 */
-	function isCriteriaMatching ($key, $value);
+	function isCriteriaMatching ($key, $value, $separator = ',');
 }
 
 // [EOF]
diff --git a/inc/classes/main/class_BaseFrameworkSystem.php b/inc/classes/main/class_BaseFrameworkSystem.php
index 2ff1eb53..679e5e4a 100644
--- a/inc/classes/main/class_BaseFrameworkSystem.php
+++ b/inc/classes/main/class_BaseFrameworkSystem.php
@@ -1412,7 +1412,7 @@ class BaseFrameworkSystem extends stdClass implements FrameworkInterface {
 	 * @param	$doExit		Whether exit the program (true is default)
 	 * @return	void
 	 */
-	public function debugBackTrace ($message = '', $doExit = true) {
+	public function debugBackTrace ($message = '', $doExit = TRUE) {
 		// Sorry, there is no other way getting this nice backtrace
 		if (!empty($message)) {
 			// Output message
diff --git a/inc/classes/main/criteria/class_BaseCriteria.php b/inc/classes/main/criteria/class_BaseCriteria.php
index b53ce648..7d59075b 100644
--- a/inc/classes/main/criteria/class_BaseCriteria.php
+++ b/inc/classes/main/criteria/class_BaseCriteria.php
@@ -146,7 +146,7 @@ class BaseCriteria extends BaseFrameworkSystem implements Criteria {
 	public final function addCriteria ($criteriaKey, $criteriaValue, $criteriaType = 'default') {
 		// Debug message
 		if (strpos($criteriaKey, 'my-') !== false) $this->debugBackTrace('criteriaKey=' . $criteriaKey);
-		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(strtoupper($criteriaType) . '-CRITERIA: criteriaKey=' . $criteriaKey . ',criteriaValue=' . $criteriaValue);
+		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(strtoupper($criteriaType) . '-CRITERIA[' . __LINE__ . ']: criteriaKey=' . $criteriaKey . ',criteriaValue=' . $criteriaValue);
 
 		// Convert dashes to underscore
 		$criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
@@ -172,7 +172,7 @@ class BaseCriteria extends BaseFrameworkSystem implements Criteria {
 	public final function addChoiceCriteria ($criteriaKey, $criteriaValue) {
 		// Debug message
 		if (strpos($criteriaKey, 'my-') !== false) $this->debugBackTrace('criteriaKey=' . $criteriaKey);
-		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CHOICE-CRITERIA: criteriaKey=' . $criteriaKey . ',criteriaValue=' . $criteriaValue);
+		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CHOICE-CRITERIA[' . __LINE__ . ']: criteriaKey=' . $criteriaKey . ',criteriaValue=' . $criteriaValue);
 
 		// Add it
 		$this->criteria['choice'][$this->convertDashesToUnderscores($criteriaKey)][] = (string) $criteriaValue;
@@ -217,7 +217,7 @@ class BaseCriteria extends BaseFrameworkSystem implements Criteria {
 		$criteriaKey = $this->convertDashesToUnderscores($criteriaKey);
 
 		// Debug message
-		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CRITERIA: criteriaKey=' . $criteriaKey . ',criteria()=' . count($this->criteria[$criteriaType]));
+		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput(strtoupper($criteriaType) . '-CRITERIA[' . __LINE__ . ']: criteriaKey=' . $criteriaKey . ',criteria()=' . count($this->criteria[$criteriaType]));
 
 		// Default is not found
 		$value = NULL;
diff --git a/inc/classes/main/criteria/search/class_SearchCriteria.php b/inc/classes/main/criteria/search/class_SearchCriteria.php
index 8d770f3e..a83f8cfa 100644
--- a/inc/classes/main/criteria/search/class_SearchCriteria.php
+++ b/inc/classes/main/criteria/search/class_SearchCriteria.php
@@ -120,28 +120,81 @@ class SearchCriteria extends BaseCriteria implements LocalSearchCriteria {
 	 *
 	 * @param	$key			Key element to check
 	 * @param	$value			Value to check
+	 * @param	$separator		Separator for "exploding" $value (default: ',')
 	 * @return	$isMatching		Whether the key/value is matching or excluded
 	 */
-	public function isCriteriaMatching ($key, $value) {
+	public function isCriteriaMatching ($key, $value, $separator = ',') {
+		// $value cannot be array
+		assert(!is_array($value));
+
+		// "Explode" value
+		$valueArray = explode($separator, $value);
+
+		// Debug message
+		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: key=' . $key . ',value=' . $value . ' - ENTERED!');
+
 		// Get 'default' search value
-		$search = $this->getCriteriaElemnent($key);
+		$searchDefault = $this->getCriteriaElemnent($key);
+
+		// Debug message
+		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: getCriteriaElement(' . $key . ')[' . gettype($searchDefault) . ']=' . $searchDefault);
 
 		// 'default' check
-		$isMatching = ((!is_null($search)) && ($search == $value));
+		$isMatching = ((!is_null($searchDefault)) && ($searchDefault == $value));
 
-		// Get 'choice' search value (can be NULL or comma-separated string)
-		$search = $this->getCriteriaChoiceElemnent($key);
+		// Debug message
+		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: getCriteriaElement(' . $key . ')[' . gettype($searchDefault) . ']=' . $searchDefault . ',isMatching=' . intval($isMatching));
+
+		// Get 'choice' search value (can be NULL or $separator-separated string)
+		$searchChoice = $this->getCriteriaChoiceElemnent($key);
+
+		// Debug message
+		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: getCriteriaChoiceElement(' . $key . ')[' . gettype($searchChoice) . ']=' . print_r($searchChoice, TRUE));
 
 		// 'choice' check
-		$isMatching = (($isMatching === TRUE) && ((is_null($search)) || (in_array($value, explode(',', $search)))));
+		if ((is_array($searchChoice)) && (count($valueArray) == 1)) {
+			// $value is a single-search value, so use in_array()
+			$isMatching = (((is_null($searchDefault)) || ($isMatching === TRUE)) && ((is_null($searchChoice)) || ((is_array($searchChoice)) && (in_array($value, $searchChoice)))));
+
+			// Debug message
+			//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: getCriteriaChoiceElement(' . $key . ')[]=' . gettype($searchChoice) . ',value=' . $value . ',isMatching=' . intval($isMatching) . ' - SINGLE-MATCH');
+		} elseif ((is_array($searchChoice)) && (count($valueArray) > 1)) {
+			// $value is choice-search value, so check all entries
+			$isMatching = ((is_null($searchDefault)) || ($isMatching === TRUE));
+			$idx = 0;
+			foreach ($valueArray as $idx => $match) {
+				// Debug message
+				//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: match=' . $match . ',count(searchChoice)=' . count($searchChoice));
+
+				// Is it found? (one is okay)
+				$isMatching = (($isMatching === TRUE) && (in_array($match, $searchChoice)));
+			} // END - foreach
+
+			// Debug message
+			/* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: getCriteriaChoiceElement(' . $key . ')[]=' . gettype($searchChoice) . ',valueArray()=' . count($valueArray) . ',idx=' . $idx . ',isMatching=' . intval($isMatching) . ' - CHOICE-MATCH');
+			die(PHP_EOL);
+		} else {
+			// Choice-match is NULL?
+			$isMatching = (($isMatching === TRUE) || (is_null($searchChoice)));
+
+			// Debug message
+			//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: getCriteriaChoiceElement(' . $key . ')[]=' . gettype($searchChoice) . ',value=' . $value . ',isMatching=' . intval($isMatching) . ' - NULL-MATCH');
+		}
+
+		// Debug message
+		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: getCriteriaChoiceElement(' . $key . ')[]=' . gettype($searchChoice) . ',isMatching=' . intval($isMatching));
 
 		// Get 'exclude' search value
-		$search = $this->getCriteriaExcludeElemnent($key);
+		$searchExclude = $this->getCriteriaExcludeElemnent($key);
+
+		// Debug message
+		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: getCriteriaExcludeElement(' . $key . ')[' . gettype($searchExclude) . ']=' . $searchExclude);
 
 		// 'exclude' check
-		$isMatching = (($isMatching === TRUE) && ((is_null($search)) || ($search != $value)));
+		$isMatching = (((is_null($searchChoice)) || ($isMatching === TRUE)) && ((is_null($searchExclude)) || ($searchExclude != $value)));
 
 		// Return result
+		//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('SEARCH-CRITERIA[' . __LINE__ . ']: key=' . $key . ',value=' . $value . ',isMatching=' . intval($isMatching) . ' - EXIT!');
 		return $isMatching;
 	}
 }
diff --git a/inc/classes/main/database/databases/class_LocalFileDatabase.php b/inc/classes/main/database/databases/class_LocalFileDatabase.php
index f4d855ff..2185039b 100644
--- a/inc/classes/main/database/databases/class_LocalFileDatabase.php
+++ b/inc/classes/main/database/databases/class_LocalFileDatabase.php
@@ -348,36 +348,41 @@ class LocalFileDatabase extends BaseDatabaseBackend implements DatabaseBackendIn
 
 				// Read the file
 				$dataArray = $this->getDataArrayFromFile($pathName . $dataFile);
-				//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: dataFile=' . $dataFile . ',dataArray='.print_r($dataArray,true));
+				//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: dataFile=' . $dataFile . ',dataArray='.print_r($dataArray, TRUE));
 
 				// Is this an array?
 				if (is_array($dataArray)) {
+					// Default is nothing found
+					$isFound = TRUE;
+
 					// Search in the criteria with FMFW (First Matches, First Wins)
 					foreach ($dataArray as $key => $value) {
-						// Is the criteria met or none set?
-						if ($searchInstance->isCriteriaMatching($key, $value)) {
-							// Shall we skip this entry?
-							if ($searchInstance->getSkip() > 0) {
-								// We shall skip some entries
-								if ($skipFound < $searchInstance->getSkip()) {
-									// Skip this entry
-									$skipFound++;
-									break;
-								} // END - if
+						// Found one entry?
+						$isFound = (($isFound === TRUE) && ($searchInstance->isCriteriaMatching($key, $value)));
+					} // END - foreach
+
+					// Is all found?
+					if ($isFound === TRUE) {
+						// Shall we skip this entry?
+						if ($searchInstance->getSkip() > 0) {
+							// We shall skip some entries
+							if ($skipFound < $searchInstance->getSkip()) {
+								// Skip this entry
+								$skipFound++;
+								break;
 							} // END - if
+						} // END - if
 
-							// Set id number
-							$dataArray[$this->getIndexKey()] = $idx;
+						// Set id number
+						$dataArray[$this->getIndexKey()] = $idx;
 
-							// Entry found!
-							//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: indexKey=' . $this->getIndexKey() . ',idx=' . $idx . ',dataArray=' . print_r($dataArray, true));
-							$resultData[BaseDatabaseBackend::RESULT_INDEX_ROWS][] = $dataArray;
+						// Entry found!
+						//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: indexKey=' . $this->getIndexKey() . ',idx=' . $idx . ',dataArray=' . print_r($dataArray, TRUE));
+						$resultData[BaseDatabaseBackend::RESULT_INDEX_ROWS][] = $dataArray;
 
-							// Count found entries up
-							$limitFound++;
-							break;
-						} // END - if
-					} // END - foreach
+						// Count found entries up
+						$limitFound++;
+					} // END - if
 				} else {
 					// Throw an exception here
 					throw new SqlException(array($this, sprintf("File &#39;%s&#39; contains invalid data.", $dataFile), self::DB_CODE_DATA_FILE_CORRUPT), self::EXCEPTION_SQL_QUERY);
@@ -476,38 +481,43 @@ class LocalFileDatabase extends BaseDatabaseBackend implements DatabaseBackendIn
 
 				// Open this file for reading
 				$dataArray = $this->getDataArrayFromFile($pathName . $dataFile);
-				//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: dataFile=' . $dataFile . ',dataArray='.print_r($dataArray,true));
+				//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: dataFile=' . $dataFile . ',dataArray='.print_r($dataArray, TRUE));
 
 				// Is this an array?
 				if (is_array($dataArray)) {
+					// Default is nothing found
+					$isFound = TRUE;
+
 					// Search in the criteria with FMFW (First Matches, First Wins)
 					foreach ($dataArray as $key => $value) {
-						// Is the criteria met?
-						if ($searchInstance->isCriteriaMatching($key, $value))  {
-							// Shall we skip this entry?
-							if ($searchInstance->getSkip() > 0) {
-								// We shall skip some entries
-								if ($skipFound < $searchInstance->getSkip()) {
-									// Skip this entry
-									$skipFound++;
-									break;
-								} // END - if
+						// Found one entry?
+						$isFound = (($isFound === TRUE) && ($searchInstance->isCriteriaMatching($key, $value)));
+					} // END - foreach
+
+					// Is all found?
+					if ($isFound === TRUE) {
+						// Shall we skip this entry?
+						if ($searchInstance->getSkip() > 0) {
+							// We shall skip some entries
+							if ($skipFound < $searchInstance->getSkip()) {
+								// Skip this entry
+								$skipFound++;
+								break;
 							} // END - if
+						} // END - if
 
-							// Entry found, so update it
-							foreach ($searchArray as $searchKey => $searchValue) {
-								//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: criteriaKey=' . $searchKey . ',criteriaValue=' . $searchValue);
-								$dataArray[$searchKey] = $searchValue;
-							} // END - foreach
+						// Entry found, so update it
+						foreach ($searchArray as $searchKey => $searchValue) {
+							//* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('DATABASE: criteriaKey=' . $searchKey . ',criteriaValue=' . $searchValue);
+							$dataArray[$searchKey] = $searchValue;
+						} // END - foreach
 
-							// Write the data to a local file
-							$this->writeDataArrayToFqfn($pathName . $dataFile, $dataArray);
+						// Write the data to a local file
+						$this->writeDataArrayToFqfn($pathName . $dataFile, $dataArray);
 
-							// Count it
-							$limitFound++;
-							break;
-						} // END - if
-					} // END - foreach
+						// Count found entries up
+						$limitFound++;
+					} // END - if
 				} // END - if
 			} // END - while
 
diff --git a/inc/classes/main/factories/objects/class_ObjectFactory.php b/inc/classes/main/factories/objects/class_ObjectFactory.php
index 6e4a4dc2..7426a0bc 100644
--- a/inc/classes/main/factories/objects/class_ObjectFactory.php
+++ b/inc/classes/main/factories/objects/class_ObjectFactory.php
@@ -58,9 +58,7 @@ class ObjectFactory extends BaseFactory {
 		}
 
 		// Create method name
-		$methodName = sprintf("create%s",
-			$className
-		);
+		$methodName = sprintf("create%s", $className);
 
 		// Run the user function
 		$objectInstance = call_user_func_array(array($className, $methodName), $args);
-- 
2.39.5