diff --git a/include/application.php b/include/application.php index 64f3cc6..4b13adf 100644 --- a/include/application.php +++ b/include/application.php @@ -949,10 +949,20 @@ class Application { $sExtraTables = ''; $sWhereFilter = $oFilters ? $oFilters->getWhereClause() : ''; - if($sWhereFilter) + $aOptions = $oFilters ? $oFilters->getOptions() : array('onlyDownloadable' => 'false'); + + if($sWhereFilter || $aOptions['onlyDownloadable'] == 'true') { $sExtraTables = ',appVersion'; - $sWhereFilter = " AND appVersion.appId = appFamily.appId AND $sWhereFilter"; + if($sWhereFilter) + $sWhereFilter = " AND $sWhereFilter"; + $sWhereFilter = " AND appVersion.state = 'accepted' AND appVersion.appId = appFamily.appId $sWhereFilter"; + } + + if($aOptions['onlyDownloadable'] == 'true') + { + $sExtraTables .= ',appData'; + $sWhereFilter .= " AND appData.type = 'downloadurl' AND appData.versionId = appVersion.versionId AND appData.state = 'accepted'"; } /* Should we add a limit clause to the query? */ if($iRows || $iStart) @@ -1025,6 +1035,7 @@ class Application { $oFilter->AddFilterInfo('appVersion.rating', 'Rating', array(FILTER_EQUALS, FILTER_LESS_THAN, FILTER_GREATER_THAN), FILTER_VALUES_ENUM, array('Platinum', 'Gold', 'Silver', 'Bronze', 'Garbage')); $oFilter->AddFilterInfo('appFamily.catId', 'Category', array(FILTER_EQUALS), FILTER_VALUES_ENUM, $aCatIds, $aCatNames); $oFilter->AddFilterInfo('appVersion.license', 'License', array(FILTER_EQUALS), FILTER_VALUES_ENUM, $aLicenses); + $oFilter->AddFilterInfo('onlyDownloadable', 'Only show downloadable apps', array(FILTER_OPTION_BOOL), FILTER_VALUES_OPTION_BOOL, array('false','true')); return $oFilter; } @@ -1167,10 +1178,20 @@ class Application { { $sExtraTables = ''; $sWhereFilter = $oFilters ? $oFilters->getWhereClause() : ''; - if($sWhereFilter) + $aOptions = $oFilters ? $oFilters->getOptions() : array('onlyDownloadable' => 'false'); + + if($sWhereFilter || $aOptions['onlyDownloadable'] == 'true') { $sExtraTables = ',appVersion'; - $sWhereFilter = " AND appVersion.appId = appFamily.appId AND $sWhereFilter"; + if($sWhereFilter) + $sWhereFilter = " AND $sWhereFilter"; + $sWhereFilter = " AND appVersion.appId = appFamily.appId $sWhereFilter"; + } + + if($aOptions['onlyDownloadable'] == 'true') + { + $sExtraTables .= ',appData'; + $sWhereFilter .= " AND appData.type = 'downloadurl' AND appData.versionId = appVersion.versionId"; } if($sState != 'accepted' && !application::canEdit()) diff --git a/include/db_filter.php b/include/db_filter.php index e5a556d..09fa909 100644 --- a/include/db_filter.php +++ b/include/db_filter.php @@ -14,7 +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); +define('FILTER_OPTION_BOOL', 7); /* A filter as part of an SQL query, such as something = 'somevalue' */ class Filter @@ -72,8 +72,13 @@ class Filter } } - public function getFilter() + /* Gets an SQL expression representing the current filter, for use in a WHERE clause */ + public function getExpression() { + /* We let callers handle options themselves, so don't include them in the WHERE clause */ + if($this->iType == FILTER_OPTION_BOOL) + return ''; + $sOp = $this->getOperator(); return "{$this->sColumn} $sOp '{$this->sData}'"; @@ -150,18 +155,18 @@ class FilterSet public function getWhereClause() { - $sFilter = ''; + $aFilters = array(); for($i = 0; $i < sizeof($this->aFilters); $i++) { $oFilter = $this->aFilters[$i]; - $sFilter .= $oFilter->getFilter(); + $sThisFilter = $oFilter->getExpression(); - if($i < sizeof($this->aFilters) - 1) - $sFilter .= ' AND '; + if($sThisFilter) + $aFilters[] = $sThisFilter; } - return $sFilter; + return implode($aFilters, ' AND '); } function getQuery($sTable, $iLimit = 0) diff --git a/include/db_filter_ui.php b/include/db_filter_ui.php index ed2f270..a301d5b 100644 --- a/include/db_filter_ui.php +++ b/include/db_filter_ui.php @@ -13,6 +13,7 @@ require_once('db_filter.php'); define(FILTER_VALUES_NORMAL, 1); define(FILTER_VALUES_ENUM, 2); define(FILTER_VALUES_BOOL, 3); +define(FILTER_VALUES_OPTION, 4); /* Info describing an available filter: what column it applies to, and what comparison options are available */ @@ -158,6 +159,37 @@ class FilterInterface return $shEditor; } + public function getOptionBoolEditor($iId, Filter $oFilter) + { + $sColumn = $this->escapeChars($oFilter->getColumn()); + $oColumn = $this->aFilterInfo[$oFilter->getColumn()]; + $sId = ($iId == -1) ? '' : $iId; + + $aTypes = $oColumn->getTypes(); + $iOp = $aTypes[0]; + + if($iId == -1) + { + /* The first entry in the list of choices is the default */ + $aValues = $oColumn->getValueTypeData(); + $sData = $aValues[0]; + } else + { + $sData = $oFilter->getData(); + } + + $shRet = ""; + + if($sData == 'true') + $sChecked = ' checked="checked"'; + else + $sChecked = ''; + + $shRet .= ""; + $shRet .= ' '.$oColumn->getDisplayName(); + + return $shRet; + } public function getItemEditor($iId, Filter $oFilter) { @@ -295,21 +327,12 @@ class FilterInterface public function getEditor() { - $shEditor = ''; + $shNewItemsEditor = ''; + $shCurrentItemsEditor = ''; $aCounts = array(); - $shEditor .= 'Add new filter (You don’t have to fill out all rows.)
'; - foreach($this->aFilterInfo as $oOption) - { - $oDummyFilter = new Filter($oOption->getColumn(), 0, ''); - $aTypes = $oOption->getTypes(); - - $shEditor .= $this->getItemEditor(-1, $oDummyFilter); - $shEditor .= '
'; - } - if(sizeof($this->oFilterSet->getFilters())) - $shEditor .= '
Active filters
'; + $shCurrentItemsEditor .= '
Active filters
'; foreach($this->oFilterSet->getFilters() as $oFilter) { $sColumn = $oFilter->getColumn(); @@ -317,13 +340,33 @@ class FilterInterface if(!array_key_exists($sColumn, $aCounts)) $aCounts[$sColumn] = 0; - $shEditor .= $this->getItemEditor($aCounts[$sColumn], $oFilter); - $shEditor .= '
'; + if($oFilter->getOperatorId() == FILTER_OPTION_BOOL) + $shCurrentItemsEditor .= $this->getOptionBoolEditor($aCounts[$sColumn], $oFilter); + else + $shCurrentItemsEditor .= $this->getItemEditor($aCounts[$sColumn], $oFilter); + $shCurrentItemsEditor .= '
'; $aCounts[$sColumn]++; } - return $shEditor; + $shNewItemsEditor .= 'Add new filter (You don’t have to fill out all rows.)
'; + foreach($this->aFilterInfo as $oOption) + { + $oDummyFilter = new Filter($oOption->getColumn(), 0, ''); + $aTypes = $oOption->getTypes(); + + if($oOption->getValueType() == FILTER_VALUES_OPTION_BOOL) + { + if(!array_key_exists($oOption->getColumn(), $aCounts)) + $shNewItemsEditor .= $this->getOptionBoolEditor(-1, $oDummyFilter); + } else + { + $shNewItemsEditor .= $this->getItemEditor(-1, $oDummyFilter); + } + $shNewItemsEditor .= '
'; + } + + return $shNewItemsEditor.$shCurrentItemsEditor; } public function getFilterInfo() @@ -335,11 +378,12 @@ class FilterInterface public function readInputForColumn($aClean, FilterInfo $oOption) { $aReturn = array(); + $bChangedOption = false; for($i = 0; array_key_exists('i'.$this->escapeChars($oOption->getColumn())."Op$i", $aClean); $i++) { $sColumn = $this->escapeChars($oOption->getColumn()); - $sData = query_escape_string($aClean["s{$sColumn}Data$i"]); + $sData = query_escape_string(getInput("s{$sColumn}Data$i", $aClean)); $iOp = $aClean["i{$sColumn}Op$i"]; if(!$iOp) @@ -347,6 +391,20 @@ class FilterInterface $oFilter = new Filter($oOption->getColumn(), $iOp, $sData); + /* Only show an option as an active filter if it has been changed + from the default */ + if($oOption->getValueType() == FILTER_VALUES_OPTION_BOOL) + { + /* The default option is the first entry in the list of choices */ + $aChoices = $oOption->getValueTypeData(); + $sDefault = $aChoices[0]; + if(!$sData) + $sData = 'false'; + if($sData == $sDefault) + continue; + $bChangedOption = true; + } + $aReturn[] = $oFilter; } @@ -357,7 +415,8 @@ class FilterInterface $sData = $aClean["s{$sColumn}Data"]; $iOp = $aClean["i{$sColumn}Op"]; - if($iOp && $sData) + + if($iOp && $sData && ($oOption->getValueType() != FILTER_VALUES_OPTON_BOOL || !$bChangedOoption)) { $oFilter = new Filter($oOption->getColumn(), $iOp, $sData); $aReturn[] = $oFilter; @@ -393,6 +452,29 @@ class FilterInterface return $this->oFilterSet->getFilterCount(); } + /* Returns an array of options, where the keys are the columns and the members + are the settings themselves */ + public function getOptions() + { + $aOptions = array(); + foreach($this->oFilterSet->getFilters() as $oFilter) + { + if($oFilter->getOperatorId() == FILTER_OPTION_BOOL) + $aOptions[$oFilter->getColumn()] = $oFilter->getData(); + } + foreach($this->aFilterInfo as $oFilterInfo) + { + if($oFilterInfo->getValueType() == FILTER_VALUES_OPTION_BOOL && + !array_key_exists($oFilterInfo->getColumn(), $aOptions)) + { + $aTypes = $oFilterInfo->getTypes(); + $sDefault = $aTypes[0]; + $aOptions[$oFilterInfo->getColumn()] = $sDefault; + } + } + return $aOptions; + } + public function getWhereClause() { return $this->oFilterSet->getWhereClause(); diff --git a/include/objectManager.php b/include/objectManager.php index f565185..0ae6113 100644 --- a/include/objectManager.php +++ b/include/objectManager.php @@ -1220,7 +1220,7 @@ class ObjectManager } /* Make an objectManager URL based on the object and optional parameters */ - public function makeUrl($sAction = false, $iId = false, $sTitle = false) + public function makeUrl($sAction = false, $iId = false, $sTitle = false, $bOmitFilters = false) { $sUrl = APPDB_ROOT."objectManager.php?"; @@ -1253,7 +1253,10 @@ class ObjectManager $sUrl .= "&iPage=".$this->oMultiPage->iPage; } - if($this->oFilters) + /* Some times it is necessary to omit the filter data, for instance when using + makeUrl() to form the action element of a form tag. This is because having + filter data present may prevent clearing a filter */ + if($this->oFilters && !$bOmitFilters) $sUrl .= $this->oFilters->getUrlData(); if($this->oSortInfo && $this->oSortInfo->sCurrentSort) @@ -1338,9 +1341,9 @@ class ObjectManager /* Show filter info */ if($this->oFilters) { - echo "
makeUrl()."\" >"; + echo "makeUrl(false, false, false, true)."\" >"; - echo $this->oFilters->getEditor(); + echo $this->oFilters->getEditor(); echo "
"; echo "
";