Integrate filtering system with objectManager, use it for applications

This commit is contained in:
Alexander Nicolaysen Sørnes
2008-04-14 01:26:37 +02:00
committed by Chris Morgan
parent b2adeab95a
commit 4f792a28ba
5 changed files with 266 additions and 38 deletions

View File

@@ -11,6 +11,7 @@ require_once(BASE."include/util.php");
require_once(BASE."include/mail.php");
require_once(BASE."include/maintainer.php");
require_once(BASE."include/tableve.php");
require_once(BASE."include/db_filter_ui.php");
define("PLATINUM_RATING", "Platinum");
define("GOLD_RATING", "Gold");
@@ -939,11 +940,18 @@ class Application {
return 'appId';
}
public static function objectGetEntries($sState, $iRows = 0, $iStart = 0, $sOrderBy = "appId", $bAscending = TRUE)
public static function objectGetEntries($sState, $iRows = 0, $iStart = 0, $sOrderBy = "appId", $bAscending = TRUE, $oFilters = null)
{
$sLimit = "";
$sOrdering = $bAscending ? "ASC" : "DESC";
$sExtraTables = '';
$sWhereFilter = $oFilters ? $oFilters->getWhereClause() : '';
if($sWhereFilter)
{
$sExtraTables = ',appVersion';
$sWhereFilter = " AND appVersion.appId = appFamily.appId AND $sWhereFilter";
}
/* Should we add a limit clause to the query? */
if($iRows || $iStart)
{
@@ -955,10 +963,10 @@ class Application {
$iRows = application::objectGetEntriesCount($sState);
}
$sQuery = "SELECT appFamily.*, vendor.vendorName AS vendorName FROM appFamily, vendor WHERE
$sQuery = "SELECT DISTINCT(appFamily.appId), appFamily.*, vendor.vendorName AS vendorName FROM appFamily, vendor$sExtraTables WHERE
appFamily.vendorId = vendor.vendorId
AND
appFamily.state = '?'";
appFamily.state = '?'$sWhereFilter";
if($sState != 'accepted' && !application::canEdit())
{
@@ -997,6 +1005,14 @@ class Application {
return $hResult;
}
public static function objectGetFilterInfo()
{
$oFilter = new FilterInterface();
$oFilter->AddFilterInfo('appVersion.rating', 'Rating', array(FILTER_EQUALS, FILTER_LESS_THAN, FILTER_GREATER_THAN), FILTER_VALUES_ENUM, array('Platinum', 'Gold', 'Silver', 'Bronze', 'Garbage'));
return $oFilter;
}
public static function objectGetSortableFields()
{
return array('submitTime', 'appName', 'appId', 'userName', 'vendorName');
@@ -1112,23 +1128,31 @@ class Application {
}
}
public static function objectGetEntriesCount($sState)
public static function objectGetEntriesCount($sState, $oFilters = null)
{
$sExtraTables = '';
$sWhereFilter = $oFilters ? $oFilters->getWhereClause() : '';
if($sWhereFilter)
{
$sExtraTables = ',appVersion';
$sWhereFilter = " AND appVersion.appId = appFamily.appId AND $sWhereFilter";
}
if($sState != 'accepted' && !application::canEdit())
{
/* Without edit rights users can only resubmit their rejected entries */
if(!$bRejected)
return FALSE;
$sQuery = "SELECT COUNT(appId) as count FROM appFamily WHERE
$sQuery = "SELECT COUNT(DISTINCT(appFamily.appId)) as count FROM appFamily$sExtraTables WHERE
submitterId = '?'
AND
state = '?'";
appFamily.state = '?'$sWhereFilter";
$hResult = query_parameters($sQuery, $_SESSION['current']->iUserId,
$sState);
} else
{
$sQuery = "SELECT COUNT(appId) as count FROM appFamily WHERE state = '?'";
$sQuery = "SELECT COUNT(DISTINCT(appFamily.appId)) as count FROM appFamily$sExtraTables WHERE appFamily.state = '?'$sWhereFilter";
$hResult = query_parameters($sQuery, $sState);
}

View File

@@ -14,6 +14,7 @@ define('FILTER_GREATER_THAN', 3);
define('FILTER_LESS_THAN', 4);
define('FILTER_NOT_EQUALS', 5);
define('FILTER_NOT_LIKE', 6);
define('FILTER_ENUM', 7);
/* A filter as part of an SQL query, such as something = 'somevalue' */
class Filter

View File

@@ -10,6 +10,10 @@
require_once('db_filter.php');
define(FILTER_VALUES_NORMAL, 1);
define(FILTER_VALUES_ENUM, 2);
define(FILTER_VALUES_BOOL, 3);
/* Info describing an available filter: what column it applies to,
and what comparison options are available */
class FilterInfo
@@ -17,12 +21,22 @@ class FilterInfo
private $sColumn;
private $sDisplayName;
private $aTypes; // Available filters for this column
private $iValueType; // Normal, enum ...
private $aValueTypeData; // List of enums
private $aValueTypeDataDisplay; // Optional display names for enums
public function FilterInfo($sColumn, $sDisplayName, $aTypes)
public function FilterInfo($sColumn, $sDisplayName, $aTypes, $iValueType = FILTER_VALUES_NORMAL, $aValueTypeData = array(), $aValueTypeDisplay = array())
{
$this->sColumn = $sColumn;
$this->sDisplayName = $sDisplayName;
$this->aTypes = $aTypes;
$this->iValueType = $iValueType;
$this->aValueTypeData = $aValueTypeData;
if(sizeof($aValueTypeData) && !sizeof($aValueTypeDisplay))
$this->aValueTypeDataDisplay = $aValueTypeData;
else
$this->aValueTypeDataDisplay = $aValueTypeDisplay;
}
public function getColumn()
@@ -35,6 +49,21 @@ class FilterInfo
return $this->sDisplayName;
}
public function getValueType()
{
return $this->iValueType;
}
public function getValueTypeData()
{
return $this->aValueTypeData;
}
public function getValueTypeDataDisplay()
{
return $this->aValueTypeDataDisplay;
}
public function getTypes()
{
return $this->aTypes;
@@ -65,11 +94,15 @@ class FilterInterface
{
private $aFilterInfo;
private $oFilterSet;
private $aEscapeChars;
private $aEscapeCharsWith;
public function FilterInterface($sTableName = '')
{
$this->aFilterInfo = array();
$this->oFilterSet = new FilterSet(mysql_real_escape_string($sTableName));
$this->oFilterSet = new FilterSet(query_escape_string($sTableName));
$this->aEscapeChars = array('.');
$this->aEscapeCharsWith = array('-');
}
public function AddFilterObject(Filter $oFilter)
@@ -83,15 +116,53 @@ class FilterInterface
}
/* Convenience function to add a filter option */
public function AddFilterInfo($sColumn, $sDisplayName, $aTypes)
public function AddFilterInfo($sColumn, $sDisplayName, $aTypes, $iValueType = VALUE_TYPE_NORMAL, $aValueTypeData = array(), $aValueTypeDisplay = array())
{
$this->aFilterInfo[$sColumn] = new FilterInfo($sColumn, $sDisplayName, $aTypes);
$this->aFilterInfo[$sColumn] = new FilterInfo($sColumn, $sDisplayName, $aTypes, $iValueType, $aValueTypeData, $aValueTypeDisplay);
}
/* We can't use some special chars in variable names, such as '.' */
public function escapeChars($sIn)
{
return str_replace($this->aEscapeChars, $this->aEscapeCharsWith, $sIn);
}
public function unescapeChars($sIn)
{
return str_replace($this->aEscapeWith, $this->aEscape, $sIn);
}
public function getUrlElement($iId, Filter $oFilter)
{
$sColumn = $this->escapeChars($oFilter->getColumn());
$oColumn = $this->aFilterInfo[$sColumn];
$sId = $iId;
$shEditor = "&i{$sColumn}Op$sId={$oFilter->getOperatorId()}";
$shEditor .= "&s{$sColumn}Data$sId={$oFilter->getData()}";
return $shEditor;
}
public function getHiddenInputTag($iId, Filter $oFilter)
{
$sColumn = $this->escapeChars($oFilter->getColumn());
$oColumn = $this->aFilterInfo[$sColumn];
$sId = $iId;
$shEditor = "<input type=\"hidden\" name=\"i{$sColumn}Op$sId\" value=\"{$oFilter->getOperatorId()}\">";
$shEditor .= "<input type=\"hidden\" name=\"s{$sColumn}Data$sId\" value=\"{$oFilter->getData()}\" />";
return $shEditor;
}
public function getItemEditor($iId, Filter $oFilter)
{
$sColumn = $oFilter->getColumn();
$oColumn = $this->aFilterInfo[$sColumn];
$sColumn = $this->escapeChars($oFilter->getColumn());
$oColumn = $this->aFilterInfo[$oFilter->getColumn()];
$sId = ($iId == -1) ? '' : $iId;
$shEditor = $oColumn->getDisplayName();
@@ -121,7 +192,90 @@ class FilterInterface
$shEditor .= '</select> ';
switch($oColumn->getValueType())
{
case FILTER_VALUES_NORMAL:
$shEditor .= "<input type='text' value=\"{$oFilter->getData()}\" name='s{$sColumn}Data$sId' size='30' />";
break;
case FILTER_VALUES_ENUM:
$shEditor .= $this->getEnumEditor($oColumn, $oFilter, $sId);
break;
}
return $shEditor;
}
public function getEnumEditor($oColumn, $oFilter, $sId)
{
$sColumn = $this->escapeChars($oFilter->getColumn());
$aOptions = $oColumn->getValueTypeData();
$aOptionNames = $oColumn->getValueTypeDataDisplay();
$sData = $oFilter->getData();
$shEditor .= "<select name=\"s{$sColumn}Data$sId\">";
if($sData)
$shEditor .= "<option value=\"\">-- remove --</option>";
else
$shEditor .= "<option value=\"\">-- select --</option>";
for($i = 0; $i < sizeof($aOptions); $i++)
{
$sOption = $aOptions[$i];
$sSelected = '';
if($sData == $sOption)
$sSelected = ' selected="selected"';
$shEditor .= "<option value=\"$sOption\"$sSelected>{$aOptionNames[$i]}</option>";
}
$shEditor .= "</select>";
return $shEditor;
}
/* Get filter data formatted to fit in a URL */
public function getUrlData()
{
$shEditor = '';
$aCounts = array();
foreach($this->oFilterSet->getFilters() as $oFilter)
{
$sColumn = $oFilter->getColumn();
if(!array_key_exists($sColumn, $aCounts))
$aCounts[$sColumn] = 0;
$shEditor .= $this->getUrlElement($aCounts[$sColumn], $oFilter);
$shEditor .= '<br />';
$aCounts[$sColumn]++;
}
return $shEditor;
}
/* Get a list of hidden input tags to preserve form data */
public function getHiddenFormData()
{
$shEditor = '';
$aCounts = array();
foreach($this->oFilterSet->getFilters() as $oFilter)
{
$sColumn = $oFilter->getColumn();
if(!array_key_exists($sColumn, $aCounts))
$aCounts[$sColumn] = 0;
$shEditor .= $this->getHiddenInputTag($aCounts[$sColumn], $oFilter);
$shEditor .= '<br />';
$aCounts[$sColumn]++;
}
return $shEditor;
}
@@ -131,16 +285,18 @@ class FilterInterface
$shEditor = '';
$aCounts = array();
$shEditor .= 'Add new filter<br />';
$shEditor .= '<b>Add new filter</b> <i>(You don&#8217;t have to fill out all rows.)</i><br />';
foreach($this->aFilterInfo as $oOption)
{
$oDummyFilter = new Filter($oOption->getColumn(), 0, '');
$aTypes = $oOption->getTypes();
$shEditor .= $this->getItemEditor(-1, $oDummyFilter);
$shEditor .= '<br />';
}
if(sizeof($this->oFilterSet->getFilters()))
$shEditor .= '<br />Active filters<br />';
$shEditor .= '<br /><b>Active filters</b><br />';
foreach($this->oFilterSet->getFilters() as $oFilter)
{
$sColumn = $oFilter->getColumn();
@@ -167,23 +323,26 @@ class FilterInterface
{
$aReturn = array();
for($i = 0; array_key_exists('i'.$oOption->getColumn()."Op$i", $aClean); $i++)
for($i = 0; array_key_exists('i'.$this->escapeChars($oOption->getColumn())."Op$i", $aClean); $i++)
{
$sData = mysql_real_escape_string($aClean["s{$oOption->getColumn()}Data$i"]);
$iOp = $aClean["i{$oOption->getColumn()}Op$i"];
$sColumn = $this->escapeChars($oOption->getColumn());
$sData = query_escape_string($aClean["s{$sColumn}Data$i"]);
$iOp = $aClean["i{$sColumn}Op$i"];
if(!$iOp)
continue;
$oFilter = new Filter($oOption->getColumn(), $iOp, $sData);
$aReturn[] = $oFilter;
}
if(array_key_exists('i'.$oOption->getColumn()."Op", $aClean))
if(array_key_exists('i'.$this->escapeChars($oOption->getColumn())."Op", $aClean))
{
$sColumn = $this->escapeChars($oOption->getColumn());
$i = sizeof($aReturn);
$sData = $aClean["s{$oOption->getColumn()}Data"];
$iOp = $aClean["i{$oOption->getColumn()}Op"];
$sData = $aClean["s{$sColumn}Data"];
$iOp = $aClean["i{$sColumn}Op"];
if($iOp)
{
@@ -208,12 +367,12 @@ class FilterInterface
public function loadTable($sTableName)
{
$this->oFilterSet->loadTable(mysql_real_escape_string($sTableName));
$this->oFilterSet->loadTable($sTableName);
}
public function saveTable($sTableName)
{
$this->oFilterSet->saveTable(mysql_real_escape_string($sTableName));
$this->oFilterSet->saveTable($sTableName);
}
public function getFilterCount()
@@ -221,6 +380,11 @@ class FilterInterface
return $this->oFilterSet->getFilterCount();
}
public function getWhereClause()
{
return $this->oFilterSet->getWhereClause();
}
public function getTable($sTable, $iLimit = 0)
{
$hResult = $this->oFilterSet->getMatchedItems($sTable, $iLimit);

View File

@@ -14,6 +14,7 @@ class ObjectManager
private $sReturnTo;
private $sReturnToTitle; /* Used to preserve the title when processing entries from a queue list, for instance */
private $oMultiPage;
private $oFilters; /* Currently active filters in table view */
private $oTableRow;
private $oSortInfo; /* Contains sort info used when displaying tables */
private $oObject; /* Store an instance of the object of the class
@@ -63,6 +64,12 @@ class ObjectManager
return $this->sState;
}
public function getFilterInfoFromInput($aClean)
{
if($this->oFilters)
$this->oFilters->readInput($aClean);
}
public function setState($sState)
{
/* Ensure that the given state is valid */
@@ -126,6 +133,7 @@ class ObjectManager
$this->oMultiPage = new MultiPage(FALSE);
$this->oTableRow = new OMTableRow(null);
$this->sState = 'accepted';
$this->oFilters = $this->getOptionalSetting('objectGetFilterInfo', FALSE);
// initialize the common responses array
$this->aCommonResponses = array();
@@ -278,6 +286,8 @@ class ObjectManager
if(!$this->oSortInfo->sCurrentSort)
$this->oSortInfo->sCurrentSort = $this->getOptionalSetting('objectGetDefaultSort', '');
$this->handleFilterControls($aClean);
/* query the class for its entries */
/* We pass in queue states to tell the object */
/* if we are requesting a list of its queued objects or */
@@ -286,10 +296,16 @@ class ObjectManager
$this->oMultiPage->iItemsPerPage,
$this->oMultiPage->iLowerLimit,
$this->oSortInfo->sCurrentSort,
$this->oSortInfo->bAscending);
$this->oSortInfo->bAscending,
$this->oFilters);
/* did we get any entries? */
if(!$hResult || query_num_rows($hResult) == 0)
{
if($this->oFilters->getFilterCount())
{
echo '<center>No matches found</center>';
} else
{
switch($this->getQueueString($this->getIsQueue(), $this->sState == 'rejected'))
{
@@ -304,6 +320,7 @@ class ObjectManager
"present</center>";
break;
}
}
if($this->GetOptionalSetting("objectShowAddEntry", FALSE))
{
@@ -1236,6 +1253,9 @@ class ObjectManager
$sUrl .= "&amp;iPage=".$this->oMultiPage->iPage;
}
if($this->oFilters)
$sUrl .= $this->oFilters->getUrlData();
if($this->oSortInfo && $this->oSortInfo->sCurrentSort)
{
$sUrl .= "&amp;sOrderBy={$this->oSortInfo->sCurrentSort}";
@@ -1267,6 +1287,9 @@ class ObjectManager
$this->oMultiPage->iPage."\">\n";
}
if($this->oFilters)
$sReturn .= $this->oFilters->getHiddenFormData();
if($this->sReturnToTitle)
$sReturn .= "<input type=\"hidden\" name=\"sReturnToTitle\" value=\"".$this->sReturnToTitle."\">\n";
@@ -1310,6 +1333,20 @@ class ObjectManager
echo $oTableRow->GetString();
}
private function handleFilterControls($aClean)
{
/* Show filter info */
if($this->oFilters)
{
echo "<form method=\"post\" action=\"".$this->makeUrl()."\" >";
echo $this->oFilters->getEditor();
echo "<br><input type='submit' value='Submit' name='sSubmit' >";
echo "</form>";
}
}
private function handleMultiPageControls($aClean, $bItemsPerPageSelector = TRUE)
{
/* Display multi-page browsing controls (prev, next etc.) if applicable.
@@ -1361,7 +1398,7 @@ class ObjectManager
$sControls .= "</form>";
}
$iTotalEntries = $oObject->objectGetEntriesCount($this->sState);
$iTotalEntries = $oObject->objectGetEntriesCount($this->sState, $this->oFilters);
$iNumPages = ceil($iTotalEntries / $iItemsPerPage);
if($iNumPages == 0)
$iNumPages = 1;

View File

@@ -23,6 +23,7 @@ require_once(BASE.'include/application_queue.php');
require_once(BASE.'include/version_queue.php');
require_once(BASE.'include/testData_queue.php');
require_once(BASE.'include/bugs.php');
require_once(BASE.'include/db_filter_ui.php');
/* if we have no valid class name we should abort */
if(!isset($aClean['sClass']))
@@ -59,6 +60,7 @@ if(isset($aClean['sReturnTo']))
$oObject->getMultiPageDataFromInput($aClean);
$oObject->setSortInfo($aClean);
$oObject->getFilterInfoFromInput($aClean);
$sClass = $oObject->getClass();
$oOtherObject = new $sClass($oObject->getId());