diff --git a/inc/core/Dataset/Query.php b/inc/core/Dataset/Query.php index 8faedd0b34..122050e002 100644 --- a/inc/core/Dataset/Query.php +++ b/inc/core/Dataset/Query.php @@ -305,7 +305,7 @@ protected function collectColumnsForKeys(array $keys) */ protected function defaultColumns() { - return array_merge(array('sportid', 'time', 'use_vdot'), $this->AdditionalColumns); + return array_merge(array('sportid', 'time', 'use_vdot', 'is_track'), $this->AdditionalColumns); } /** diff --git a/inc/training/search/class.FormularSelectSearchSort.php b/inc/training/search/class.FormularSelectSearchSort.php index 87993a6e36..19c08d1ed4 100644 --- a/inc/training/search/class.FormularSelectSearchSort.php +++ b/inc/training/search/class.FormularSelectSearchSort.php @@ -3,12 +3,18 @@ * This file contains class::FormularSelectSearchSort * @package Runalyze\HTML\Formular */ + +use Runalyze\Dataset\Keys; + /** * Class for a double field for sort value and order * @author Hannes Christiansen * @package Runalyze\HTML\Formular */ class FormularSelectSearchSort extends FormularField { + /** @var array */ + protected $SortByOptions = []; + /** * Validate value * @return boolean @@ -25,30 +31,61 @@ protected function getFieldCode() { $code = ''; $code .= '
'; - $sortByOptions = array( - 'time' => __('Date'), - 'distance' => __('Distance'), - 's' => __('Duration'), - 'pace' => __('Pace'), - 'elevation' => __('Elevation'), - 'pulse_avg' => __('avg. Heartrate'), - 'pulse_max' => __('max. Heartrate'), - 'temperature' => __('Temperature'), - 'cadence' => __('Cadence'), - 'stride_length' => __('Stride length'), - 'groundcontact' => __('Ground contact'), - 'vertical_oscillation' => __('Vertical oscillation'), - 'vertical_ratio' => __('Vertical ratio'), - 'vdot' => __('VDOT'), - 'trimp' => __('TRIMP'), - 'jd_intensity' => __('JDpoints') - ); - - $code .= HTML::selectBox('search-sort-by', $sortByOptions); + $this->addOptionsFor([ + ['time', __('Date')], + Keys::DISTANCE, + Keys::DURATION, + ['pace', __('Pace')], + Keys::ELAPSED_TIME, + Keys::ELEVATION, + ['gradient', __('Gradient')], + Keys::HEARTRATE_AVG, + Keys::HEARTRATE_MAX, + Keys::TRIMP, + Keys::RPE, + Keys::JD_INTENSITY, + Keys::CALORIES, + Keys::VDOT_VALUE, + Keys::POWER, + Keys::CADENCE, + Keys::STRIDE_LENGTH, + Keys::GROUNDCONTACT, + Keys::GROUNDCONTACT_BALANCE, + Keys::VERTICAL_OSCILLATION, + Keys::VERTICAL_RATIO, + Keys::TOTAL_STROKES, + Keys::SWOLF, + Keys::FIT_VO2MAX_ESTIMATE, + Keys::FIT_RECOVERY_TIME, + Keys::FIT_HRV_ANALYSIS, + Keys::FIT_TRAINING_EFFECT, + Keys::FIT_PERFORMANCE_CONDITION, + Keys::TEMPERATURE, + ['wind_speed', __('Wind speed')], + ['wind_deg', __('Wind direction')], + Keys::HUMIDITY, + Keys::AIR_PRESSURE + ]); + + $code .= HTML::selectBox('search-sort-by', $this->SortByOptions); $code .= HTML::selectBox('search-sort-order', array('DESC' => __('descending'), 'ASC' => __('ascending'))); $code .= '
'; return $code; } + + /** + * @param array $keyIds + */ + protected function addOptionsFor(array $keyIds) { + foreach ($keyIds as $keyIdOrArray) { + if (is_array($keyIdOrArray)) { + $this->SortByOptions[$keyIdOrArray[0]] = $keyIdOrArray[1]; + } else { + $Key = Keys::get($keyIdOrArray); + $this->SortByOptions[$Key->column()] = $Key->label(); + } + } + } } \ No newline at end of file diff --git a/inc/training/search/class.SearchFormular.php b/inc/training/search/class.SearchFormular.php index 4627809e98..fed14738f2 100644 --- a/inc/training/search/class.SearchFormular.php +++ b/inc/training/search/class.SearchFormular.php @@ -8,6 +8,8 @@ use Runalyze\Data\Weather\Humidity; use Runalyze\Data\Weather\WindSpeed; use Runalyze\Data\Weather\Pressure; +use Runalyze\Dataset; + /** * Search formular * @@ -157,41 +159,58 @@ protected function initConditions() { $this->addConditionFieldWithChosen('typeid', 'type', 'name', __('Type'), __('Choose activity type(s)')); $this->addConditionFieldWithChosen('weatherid', 'weather', 'name', __('Weather'), __('Choose weather conditions')); $this->addConditionFieldWithChosen('equipmentid', 'equipment', 'name', __('Equipment'), __('Choose equipment')); - $this->addConditionFieldWithChosen('tagid', 'tag', 'tag', __('Tag'), __('Choose tag')); - + $this->addConditionFieldWithChosen('tagid', 'tag', 'tag', __('Tag'), __('Choose tag')); $this->addFieldNotes(); + // Currently there's a fixed 3-column layout + // We try to order the fields column-wise, not row-wise $this->addNumericConditionField('distance', __('Distance'), FormularInput::$SIZE_SMALL, Configuration::General()->distanceUnitSystem()->distanceUnit()); $this->addNumericConditionField('elevation', __('Elevation'), FormularInput::$SIZE_SMALL, Configuration::General()->distanceUnitSystem()->elevationUnit()); $this->addStringConditionField('route', __('Route'), FormularInput::$SIZE_MIDDLE); + $this->addDurationField('s', __('Duration')); - $this->addNumericConditionField('temperature', __('Temperature'), FormularInput::$SIZE_SMALL, Configuration::General()->temperatureUnit()->unit()); - $this->addNumericConditionField('humidity', __('Humidity'), FormularInput::$SIZE_SMALL, (new Humidity())->unit()); - $this->addNumericConditionField('pressure', __('Pressure'), FormularInput::$SIZE_SMALL, (new Pressure())->unit()); - $this->addNumericConditionField('wind_speed', __('Wind Speed'), FormularInput::$SIZE_SMALL, (new WindSpeed())->unit()); + $this->addNumericConditionField('gradient', __('Gradient'), FormularInput::$SIZE_SMALL, FormularUnit::$PERCENT); $this->addStringConditionField('comment', __('Title'), FormularInput::$SIZE_MIDDLE); - $this->addNumericConditionField('pulse_avg', __('avg. HR'), FormularInput::$SIZE_SMALL, FormularUnit::$BPM); - $this->addNumericConditionField('kcal', __('Calories'), FormularInput::$SIZE_SMALL, FormularUnit::$KCAL); - $this->addStringConditionField('partner', __('Partner'), FormularInput::$SIZE_MIDDLE); - $this->addNumericConditionField('pulse_max', __('max. HR'), FormularInput::$SIZE_SMALL, FormularUnit::$BPM); + + $this->addNumericConditionField('pace', __('Pace'), FormularInput::$SIZE_SMALL, FormularUnit::$PACE); $this->addNumericConditionField('cadence', __('Cadence'), FormularInput::$SIZE_SMALL, FormularUnit::$SPM); + $this->addStringConditionField('partner', __('Partner'), FormularInput::$SIZE_MIDDLE); + + $this->addNumericConditionField('pulse_avg', __('avg. HR'), FormularInput::$SIZE_SMALL, FormularUnit::$BPM); + $this->addNumericConditionField('stride_length', __('Stride length'), FormularInput::$SIZE_SMALL, Configuration::General()->distanceUnitSystem()->strideLengthUnit()); $this->addBooleanField('is_public', __('Is public')); - $this->addNumericConditionField('jd_intensity', __('JD points'), FormularInput::$SIZE_SMALL); - $this->addNumericConditionField('groundcontact', __('Ground contact'), FormularInput::$SIZE_SMALL, FormularUnit::$MS); - $this->addNumericConditionField('groundcontact_balance', __('Ground Contact Balance'), FormularInput::$SIZE_SMALL, 'L'. FormularUnit::$PERCENT); + + $this->addNumericConditionField('pulse_max', __('max. HR'), FormularInput::$SIZE_SMALL, FormularUnit::$BPM); + $this->addNumericConditionFIeld('power', __('Power'), FormularInput::$SIZE_SMALL, FormularUnit::$POWER); + $this->addBooleanField('is_race', __('Is race')); + + $this->addNumericConditionField(Configuration::Vdot()->useElevationCorrection() ? 'vdot_with_elevation' : 'vdot', __('VDOT'), FormularInput::$SIZE_SMALL); $this->addNumericConditionField('vertical_oscillation', __('Vertical oscillation'), FormularInput::$SIZE_SMALL, FormularUnit::$CM); - $this->addNumericConditionField('vertical_ratio', __('Vertical ratio'), FormularInput::$SIZE_SMALL, FormularUnit::$PERCENT); - $this->addNumericConditionField('stride_length', __('Stride length'), FormularInput::$SIZE_SMALL, Configuration::General()->distanceUnitSystem()->strideLengthUnit()); - if(Configuration::Vdot()->useElevationCorrection()) { - $this->addNumericConditionField('vdot_with_elevation', __('VDOT'), FormularInput::$SIZE_SMALL); - } else { - $this->addNumericConditionField('vdot', __('VDOT'), FormularInput::$SIZE_SMALL); - } $this->addBooleanField('use_vdot', __('Uses VDOT')); + $this->addNumericConditionField('trimp', __('TRIMP'), FormularInput::$SIZE_SMALL); + $this->addNumericConditionField('vertical_ratio', __('Vertical ratio'), FormularInput::$SIZE_SMALL, FormularUnit::$PERCENT); + $this->addBooleanField('is_track', __('Track')); + $this->addNumericConditionField('rpe', __('RPE'), FormularInput::$SIZE_SMALL); + $this->addNumericConditionField('groundcontact', __('Ground contact'), FormularInput::$SIZE_SMALL, FormularUnit::$MS); + $this->addNumericConditionField('temperature', __('Temperature'), FormularInput::$SIZE_SMALL, Configuration::General()->temperatureUnit()->unit()); + + $this->addNumericConditionField('jd_intensity', __('JD points'), FormularInput::$SIZE_SMALL); + $this->addNumericConditionField('groundcontact_balance', __('Ground Contact Balance'), FormularInput::$SIZE_SMALL, 'L'. FormularUnit::$PERCENT); + $this->addNumericConditionField('wind_speed', __('Wind Speed'), FormularInput::$SIZE_SMALL, (new WindSpeed())->unit()); + + $this->addNumericConditionField('kcal', __('Calories'), FormularInput::$SIZE_SMALL, FormularUnit::$KCAL); $this->addNumericConditionField('fit_training_effect', __('Training Effect'), FormularInput::$SIZE_SMALL); + $this->addNumericConditionField('humidity', __('Humidity'), FormularInput::$SIZE_SMALL, (new Humidity())->unit()); + + $this->addNumericConditionField('fit_vdot_estimate', Dataset\Keys::get(Dataset\Keys::FIT_VO2MAX_ESTIMATE)->label(), FormularInput::$SIZE_SMALL); + $this->addNumericConditionField('fit_recovery_time', Dataset\Keys::get(Dataset\Keys::FIT_RECOVERY_TIME)->label(), FormularInput::$SIZE_SMALL); + $this->addNumericConditionField('pressure', __('Pressure'), FormularInput::$SIZE_SMALL, (new Pressure())->unit()); + + // Currently missing/not supported: + // elapsed_time, fit_hrv_analysis, fit_performance_condition, total_strokes, swolf, wind_deg, is_night } /** diff --git a/inc/training/search/class.SearchResults.php b/inc/training/search/class.SearchResults.php index 12b5243d19..3e732e9e05 100644 --- a/inc/training/search/class.SearchResults.php +++ b/inc/training/search/class.SearchResults.php @@ -7,6 +7,7 @@ use Runalyze\Activity\Distance; use Runalyze\Activity\Duration; use Runalyze\Activity\Elevation; +use Runalyze\Activity\Pace; use Runalyze\Activity\StrideLength; use Runalyze\Configuration; use Runalyze\Util\LocalTime; @@ -26,11 +27,17 @@ class SearchResults { const MAX_LIMIT_FOR_MULTI_EDITOR = 100; /** - * Allowed keys + * Allowed keys to search for * @var array */ protected $AllowedKeys = array(); + /** @var array */ + protected $KeysThatShouldIgnoreNull = array(); + + /** @var array */ + protected $KeysThatShouldIgnoreZero = array(); + /** * Colspan * @var int @@ -88,6 +95,8 @@ public function __construct($withResults = true) { $this->ResultsPerPage = Configuration::Misc()->searchResultsPerPage(); $this->setAllowedKeys(); + $this->setKeysThatShouldIgnoreNull(); + $this->setKeysThatShouldIgnoreZero(); if ($withResults) { $this->initDataset(); @@ -97,52 +106,95 @@ public function __construct($withResults = true) { /** * Set allowed keys + * + * These keys are valid for 'sort by' and for any condition. + * `sportid` and `time` are valid anyway, they don't need to be set here. */ protected function setAllowedKeys() { + // Keys are sorted as in structure.sql $this->AllowedKeys = array( 'typeid', - 'weatherid', - + 'is_public', + 'is_track', 'distance', 's', - 'pulse_avg', - + 'elapsed_time', 'elevation', - 'temperature', - 'wind_speed', - 'humdity', - 'pressure', - 'kcal', - - 'partner', - 'route', - 'comment', - + 'pulse_avg', 'pulse_max', + 'vdot', + 'vdot_with_elevation', + 'use_vdot', + 'fit_vdot_estimate', + 'fit_recovery_time', + 'fit_hrv_analysis', + 'fit_training_effect', + 'fit_performance_condition', 'jd_intensity', 'rpe', - 'fit_training_effect', 'trimp', - 'cadence', + 'power', + 'total_strokes', + 'swolf', 'stride_length', 'groundcontact', + 'groundcontact_balance', 'vertical_oscillation', 'vertical_ratio', - 'groundcontact_balance', - - 'use_vdot', - 'vdot', - 'vdot_with_elevation', - 'is_public' + 'temperature', + 'wind_speed', + 'wind_deg', + 'humidity', + 'pressure', + 'is_night', + 'weatherid', + 'route', + 'comment', + 'partner', + 'notes' ); + } - // Some additional keys - $this->AllowedKeys[] = 'power'; - $this->AllowedKeys[] = 'is_track'; - $this->AllowedKeys[] = 'notes'; + /** + * The following keys will add a `IS NOT NULL` if they have a condition (or order by) + */ + protected function setKeysThatShouldIgnoreNull() { + $this->KeysThatShouldIgnoreNull = [ + 'fit_training_effect', + 'fit_performance_condition', + 'rpe', + 'temperature', + 'wind_speed', + 'wind_deg', + 'humidity', + 'pressure' + ]; + } + /** + * The following keys will add a `!= 0` if they have a condition (or order by) + */ + protected function setKeysThatShouldIgnoreZero() { + $this->KeysThatShouldIgnoreZero = [ + 'distance', + 'pulse_avg', + 'pulse_max', + 'vdot', + 'fit_vdot_estimate', + 'fit_recovery_time', + 'fit_hrv_analysis', + 'cadence', + 'power', + 'total_strokes', + 'swolf', + 'stride_length', + 'groundcontact', + 'groundcontact_balance', + 'vertical_oscillation', + 'vertical_ratio' + ]; } /** @@ -162,7 +214,9 @@ protected function initDataset() { * Search trainings */ protected function searchTrainings() { - $this->TotalNumberOfTrainings = DB::getInstance()->query('SELECT COUNT(*) FROM `'.PREFIX.'training` AS `t` '.$this->getWhere().$this->getOrder().' LIMIT 1')->fetchColumn(); + $where = $this->getWhere(); + + $this->TotalNumberOfTrainings = DB::getInstance()->query('SELECT COUNT(*) FROM `'.PREFIX.'training` AS `t` '.$this->joinRaceResultIfRequired().' '.$where.' LIMIT 1')->fetchColumn(); $this->Page = (int)Request::param('page'); if (($this->Page-1)*$this->ResultsPerPage > $this->TotalNumberOfTrainings) @@ -178,14 +232,38 @@ protected function searchTrainings() { ', '.$this->DatasetQuery->queryToSelectAllKeys().' '. $this->DatasetQuery->queryToSelectJoinedFields() ).' + '.$this->columnFromRaceResultIfRequired().' FROM `'.PREFIX.'training` AS `t` + '.$this->joinRaceResultIfRequired().' '.$this->DatasetQuery->queryToJoinTables().' - '.$this->getWhere().' '. + '.$where.' '. $this->DatasetQuery->queryToGroupByActivity(). - $this->getOrder().$this->getLimit() + $this->getOrder().$this->getLimit() )->fetchAll(); } + /** + * @return string + */ + protected function columnFromRaceResultIfRequired() { + if (isset($_POST['is_race']) && $_POST['is_race'] != '') { + return ', `rr`.`activity_id`'; + } + + return ''; + } + + /** + * @return string + */ + protected function joinRaceResultIfRequired() { + if (isset($_POST['is_race']) && $_POST['is_race'] != '') { + return 'LEFT JOIN `'.PREFIX.'raceresult` AS `rr` ON `t`.`id` = `rr`.`activity_id`'; + } + + return ''; + } + /** * Get where * @return string @@ -193,11 +271,7 @@ protected function searchTrainings() { protected function getWhere() { $conditions = array('`t`.`accountid`="'.$this->AccountID.'"'); - if (isset($_POST['sportid'])) - $this->addSportCondition($conditions); - - if (isset($_POST['date-from']) && isset($_POST['date-to'])) - $this->addTimeRangeCondition($conditions); + $this->addSpecialConditions($conditions); if (isset($_POST['s']) && strlen($_POST['s']) > 0) { $Time = new Duration($_POST['s']); @@ -216,7 +290,67 @@ protected function getWhere() { $this->addConditionsForOrder($conditions); - return $this->getEquipmentCondition().$this->getTagCondition().' WHERE '.implode(' AND ', $conditions); + return $this->getEquipmentCondition().$this->getTagCondition().' WHERE '.implode(' AND ', array_unique($conditions)); + } + + /** + * @param array $conditions + */ + protected function addSpecialConditions(array &$conditions) { + if (isset($_POST['sportid'])) { + $this->addSportCondition($conditions); + } + + if (isset($_POST['date-from']) && isset($_POST['date-to'])) { + $this->addTimeRangeCondition($conditions); + } + + if (isset($_POST['pace']) && $_POST['pace'] != '') { + $this->addPaceCondition($conditions); + } + + if (isset($_POST['gradient']) && $_POST['gradient'] != '') { + $this->addGradientCondition($conditions); + } + + if (isset($_POST['is_race']) && $_POST['is_race'] != '') { + $this->addIsRaceCondition($conditions); + } + } + + /** + * @param array $conditions + */ + protected function addPaceCondition(array &$conditions) { + $Pace = new Pace(0); + $Pace->fromMinPerKm($_POST['pace']); + $value = $Pace->secondsPerKm(); + $sign = $this->signForKey('pace'); + + $conditions[] = '`t`.`distance` > 0'; + $conditions[] = ($sign == '=' ? 'ROUND(`t`.`s`/`t`.`distance`)' : '`t`.`s`/`t`.`distance`').' '.$sign.' '.DB::getInstance()->escape($value); + } + + /** + * @param array $conditions + */ + protected function addGradientCondition(array &$conditions) { + $value = 10*(float)str_replace(',', '.', $_POST['gradient']); + + $conditions[] = '`t`.`distance` > 0'; + $conditions[] = '`t`.`elevation` > 0'; + $conditions[] = '`t`.`elevation`/`t`.`distance` '.$this->signForKey('gradient').' '.DB::getInstance()->escape($value); + } + + /** + * @param array $conditions + */ + protected function addIsRaceCondition(array &$conditions) { + if ($_POST['is_race'] == 1) { + $conditions[] = '`rr`.`activity_id` IS NOT NULL'; + } else { + $conditions[] = '`rr`.`activity_id` IS NULL'; + } } /** @@ -246,47 +380,63 @@ protected function addConditionFor($key, array &$conditions) { if ($sign == ' LIKE ') { $conditions[] = '`t`.`'.$key.'` '.$sign.' "%'.DB::getInstance()->escape($_POST[$key], false).'%"'; } else { - if (in_array($key, array('distance', 'vertical_oscillation', 'stride_length'))) { - $_POST[$key] = (float)str_replace(',', '.', $_POST[$key]); - } - - if ($key == 'elevation') { - $value = (new Elevation())->setInPreferredUnit($_POST[$key])->meter(); - } elseif ($key == 'distance') { - $value = (new Distance())->setInPreferredUnit($_POST[$key])->kilometer(); - } elseif ($key == 'vertical_oscillation') { - $value = 10*$_POST[$key]; - } elseif ($key == 'vertical_ratio') { - $value = 10*$_POST[$key]; - } elseif ($key == 'groundcontact_balance') { - $value = 100*$_POST[$key]; - } elseif ($key == 'stride_length') { - $value = (new StrideLength())->setInPreferredUnit($_POST[$key])->cm(); - } elseif ($key == 'temperature') { - $value = (new Temperature())->setInPreferredUnit($_POST[$key])->celsius(); - } elseif ($key == 'wind_speed') { - $value = (new WindSpeed())->setInPreferredUnit($_POST[$key])->value(); - } elseif ($key == 'vdot' || $key == 'vdot_with_elevation') { - if(!Configuration::Vdot()->useCorrectionFactor()) { - $value = $_POST[$key]; - } else { - $value = $_POST[$key] * Configuration::Data()->vdotFactor(); - } - } else { - $value = $_POST[$key]; - } + $value = $this->transformValueForDatabase($key, $_POST[$key]); $conditions[] = '`t`.`'.$key.'` '.$sign.' '.DB::getInstance()->escape($value); - if ( - ($sign == '<' || $sign == '<=') && - in_array($key, array('distance', 'pulse_avg', 'pulse_max', 'cadence', 'groundcontact', 'vertical_oscillation', 'vertical_ratio', 'groundcontact_balance', 'stride_length')) - ) { - $conditions[] = '`t`.`'.$key.'` != 0'; + if ($sign == '<' || $sign == '<=') { + if (in_array($key, $this->KeysThatShouldIgnoreZero)) { + $conditions[] = '`t`.`'.$key.'` != 0'; + } elseif (in_array($key, $this->KeysThatShouldIgnoreNull)) { + $conditions[] = '`t`.`'.$key.'` IS NOT NULL'; + } } } } + /** + * @param string $key + * @param string $value + * @return float|int + */ + protected function transformValueForDatabase($key, $value) { + if (in_array($key, array('distance', 'vertical_oscillation', 'vertical_ratio', 'stride_length', 'groundcontact_balance', 'fit_training_effect'))) { + $value = (float)str_replace(',', '.', $value); + } + + if ($key == 'elevation') { + $value = (new Elevation())->setInPreferredUnit($value)->meter(); + } elseif ($key == 'distance') { + $value = (new Distance())->setInPreferredUnit($value)->kilometer(); + } elseif ($key == 'vertical_oscillation' || $key == 'vertical_ratio') { + $value *= 10; + } elseif ($key == 'groundcontact_balance') { + $value *= 100; + } elseif ($key == 'stride_length') { + $value = (new StrideLength())->setInPreferredUnit($value)->cm(); + } elseif ($key == 'temperature') { + $value = (new Temperature())->setInPreferredUnit($value)->celsius(); + } elseif ($key == 'wind_speed') { + $value = (new WindSpeed())->setInPreferredUnit($value)->value(); + } elseif (($key == 'vdot' || $key == 'vdot_with_elevation') && Configuration::Vdot()->useCorrectionFactor()) { + $value *= Configuration::Data()->vdotFactor(); + } + + return $value; + } + + /** + * @param string $key + * @return string + */ + protected function signForKey($key) { + if (isset($_POST['opt'][$key])) { + return $this->signFor($_POST['opt'][$key]); + } + + return '='; + } + /** * Equality sign * @param string $postSign from $_POST @@ -390,18 +540,25 @@ function ($value) { * @return string */ protected function getOrder() { - $sort = (!isset($_POST['search-sort-by']) || array_key_exists($_POST['search-sort-by'], $this->AllowedKeys)) ? '`time`' : $this->DB->escape($_POST['search-sort-by'], false); $order = (!isset($_POST['search-sort-order'])) ? 'DESC' : $this->DB->escape($_POST['search-sort-order'], false); - if ($sort == 'vdot' && Configuration::Vdot()->useElevationCorrection()) { + if ($_POST['search-sort-by'] == 'vdot' && Configuration::Vdot()->useElevationCorrection()) { return ' ORDER BY IF(`t`.`vdot_with_elevation`>0, `t`.`vdot_with_elevation`, `t`.`vdot`) '.$order; } - if ($sort == 'pace') { - return ' ORDER BY IF(`t`.`distance`>0, `t`.`s`/`t`.`distance`, 0) '.$order; + if ($_POST['search-sort-by'] == 'pace') { // addConditionsForOrder() guarantees that `distance` > 0 + return ' ORDER BY `t`.`s`/`t`.`distance` '.$order; + } + + if ($_POST['search-sort-by'] == 'gradient') { // addConditionsForOrder() guarantees that `distance` > 0 + return ' ORDER BY `t`.`elevation`/`t`.`distance` '.$order; + } + + if (isset($_POST['search-sort-by']) && in_array($_POST['search-sort-by'], $this->AllowedKeys)) { + return ' ORDER BY `t`.'.$this->DB->escape($_POST['search-sort-by'], false).' '.$order; } - return ' ORDER BY `t`.'.$sort.' '.$order; + return ' ORDER BY `t`.`time` '.$order; } /** @@ -414,8 +571,13 @@ protected function addConditionsForOrder(array &$conditions) { if ($_POST['search-sort-by'] == 'pace') { $conditions[] = '`t`.`distance` > 0'; - } elseif (in_array($_POST['search-sort-by'], array('pulse_avg', 'pulse_max', 'cadence', 'stride_length', 'groundcontact', 'vertical_oscillation', 'vertical_ratio'))) { - $conditions[] = '`t`.`'.$_POST['search-sort-by'].'` > 0'; + } elseif ($_POST['search-sort-by'] == 'gradient') { + $conditions[] = '`t`.`distance` > 0'; + $conditions[] = '`t`.`elevation` > 0'; + } elseif (in_array($_POST['search-sort-by'], $this->KeysThatShouldIgnoreZero)) { + $conditions[] = '`t`.`'.$_POST['search-sort-by'].'` != 0'; + } elseif (in_array($_POST['search-sort-by'], $this->KeysThatShouldIgnoreNull)) { + $conditions[] = '`t`.`'.$_POST['search-sort-by'].'` IS NOT NULL'; } }