From 73c350e21d800fa7bf91e651ffcf851e7312259f Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Willms <tleilax+studip@gmail.com> Date: Thu, 26 Jan 2023 12:05:57 +0000 Subject: [PATCH] adjust sorm methods to count/return only distinct values, fixes #1885 Closes #1885 Merge request studip/studip!1233 --- lib/models/BlubberThread.php | 6 +-- lib/models/OERHost.php | 4 +- lib/models/SimpleORMap.class.php | 74 +++++++++++++++++++------------- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/lib/models/BlubberThread.php b/lib/models/BlubberThread.php index d0f2f89ecd7..f266223bdc3 100644 --- a/lib/models/BlubberThread.php +++ b/lib/models/BlubberThread.php @@ -101,11 +101,11 @@ class BlubberThread extends SimpleORMap implements PrivacyObject /** * @return BlubberThread[] */ - public static function findBySQL($sql, $params = []) + public static function findBySQL($condition, $params = []) { - return parent::findAndMapBySQL(function ($thread) { + return parent::findAndMapBySQL(function (BlubberThread $thread) { return self::upgradeThread($thread); - }, $sql, $params); + }, $condition, $params); } /** diff --git a/lib/models/OERHost.php b/lib/models/OERHost.php index d0b1f6928a6..f4303e33f18 100644 --- a/lib/models/OERHost.php +++ b/lib/models/OERHost.php @@ -46,9 +46,9 @@ class OERHost extends OERIdentity ]); } - public static function findBySQL($sql, $params = []) + public static function findBySQL($condition, $params = []) { - $hosts = parent::findBySQL($sql, $params); + $hosts = parent::findBySQL($condition, $params); foreach ($hosts as $key => $host) { $class = $host['sorm_class']; if ($class && ($class !== 'OERHost') && is_subclass_of($class, 'OERHost')) { diff --git a/lib/models/SimpleORMap.class.php b/lib/models/SimpleORMap.class.php index 7af9dece840..80925c32dad 100644 --- a/lib/models/SimpleORMap.class.php +++ b/lib/models/SimpleORMap.class.php @@ -484,22 +484,29 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate /** * returns number of records * - * @param ?string $sql sql clause to use on the right side of WHERE - * @param ?array $params params for query + * @param string $condition sql clause to use on the right side of WHERE + * @param array $params params for query * @return int */ - public static function countBySql($sql = '1', $params = []) + public static function countBySql($condition = '1', $params = []) { $db_table = static::db_table(); - $db = DBManager::get(); - $has_join = stripos($sql, 'JOIN '); + + $has_join = stripos($condition, 'JOIN '); if ($has_join === false || $has_join > 10) { - $sql = 'WHERE ' . $sql; + $sql = "SELECT COUNT(*) FROM `{$db_table}` WHERE {$condition}"; + } else { + $pk = implode(',', array_map( + function ($key) use ($db_table) { + return "`{$db_table}`.`{$key}`"; + }, + static::pk() + )); + + $sql = "SELECT COUNT(DISTINCT {$pk}) FROM `{$db_table}` {$condition}"; } - $sql = "SELECT count(*) FROM `" . $db_table . "` " . $sql; - $st = $db->prepare($sql); - $st->execute($params); - return (int)$st->fetchColumn(); + + return (int) DBManager::get()->fetchColumn($sql, $params); } /** @@ -608,26 +615,31 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate /** * returns array of instances of given class filtered by given sql - * @param string $sql sql clause to use on the right side of WHERE - * @param ?array $params parameters for query + * @param string $condition sql clause to use on the right side of WHERE + * @param array $params parameters for query * @return array array of "self" objects */ - public static function findBySQL($sql, $params = []) + public static function findBySQL($condition, $params = []) { $db_table = static::db_table(); - $class = get_called_class(); - $record = new $class(); - $db = DBManager::get(); - $has_join = stripos($sql, 'JOIN '); + + $has_join = stripos($condition, 'JOIN '); if ($has_join === false || $has_join > 10) { - $sql = 'WHERE ' . $sql; + $condition = "WHERE {$condition}"; + $distinct = ''; + } else { + $distinct = 'DISTINCT'; } - $sql = "SELECT `" . $db_table . "`.* FROM `" . $db_table . "` " . $sql; - $ret = []; + $sql = "SELECT {$distinct} `{$db_table}`.* FROM `{$db_table}` {$condition}"; + + $record = new static(); + $record->setNew(false); + $stmt = DBManager::get()->prepare($sql); $stmt->execute($params); $stmt->setFetchMode(PDO::FETCH_INTO , $record); - $record->setNew(false); + + $ret = []; while ($record = $stmt->fetch()) { // Reset all relations $record->cleanup(); @@ -695,23 +707,27 @@ class SimpleORMap implements ArrayAccess, Countable, IteratorAggregate * passes objects for given sql through given callback * * @param callable $callable callback which gets the current record as param - * @param string $sql where clause of sql + * @param string $condition where clause of sql * @param ?array $params sql statement parameters * @return integer number of found records */ - public static function findEachBySQL($callable, $sql, $params = []) + public static function findEachBySQL($callable, $condition, $params = []) { - $has_join = stripos($sql, 'JOIN '); + $db_table = static::db_table(); + + $has_join = stripos($condition, 'JOIN '); if ($has_join === false || $has_join > 10) { - $sql = "WHERE {$sql}"; + $condition = "WHERE {$condition}"; + $distinct = ''; + } else { + $distinct = 'DISTINCT'; } + $sql = "SELECT {$distinct} `{$db_table}`.* FROM `{$db_table}` {$condition}"; - $class = get_called_class(); - $record = new $class(); + $record = new static(); $record->setNew(false); - $db_table = static::db_table(); - $st = DBManager::get()->prepare("SELECT `{$db_table}`.* FROM `{$db_table}` {$sql}"); + $st = DBManager::get()->prepare($sql); $st->execute($params); $st->setFetchMode(PDO::FETCH_INTO , $record); -- GitLab