From bec883c70506050164e9a3769b0dc0b033d0fdee Mon Sep 17 00:00:00 2001 From: Matt Friedman Date: Wed, 12 Nov 2025 07:11:04 -0800 Subject: [PATCH 1/4] Show statistics on ideas main page --- controller/index_controller.php | 1 + factory/ideas.php | 25 ++++++++++++++++++++ language/en/common.php | 1 + styles/prosilver/template/index_body.html | 7 +++++- tests/ideas/get_statistics_test.php | 28 +++++++++++++++++++++++ 5 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 tests/ideas/get_statistics_test.php diff --git a/controller/index_controller.php b/controller/index_controller.php index dabe106..a01f499 100644 --- a/controller/index_controller.php +++ b/controller/index_controller.php @@ -54,6 +54,7 @@ public function index() 'U_VIEW_IN_PROGRESS'=> $this->helper->route('phpbb_ideas_list_controller', ['sort' => ext::SORT_DATE, 'status' => ext::$statuses['IN_PROGRESS']]), 'U_POST_ACTION' => $this->helper->route('phpbb_ideas_post_controller'), 'U_MCP' => ($this->auth->acl_get('m_', $this->config['ideas_forum_id'])) ? append_sid("{$this->root_path}mcp.$this->php_ext", "f={$this->config['ideas_forum_id']}&i=main&mode=forum_view", true, $this->user->session_id) : '', + 'STATISTICS' => $this->entity->get_statistics(), )); // Assign breadcrumb template vars diff --git a/factory/ideas.php b/factory/ideas.php index e357754..6fd2189 100644 --- a/factory/ideas.php +++ b/factory/ideas.php @@ -296,4 +296,29 @@ public function get_idea_count() { return $this->idea_count ?? 0; } + + /** + * Get total ideas statistics + * + * @return array + */ + public function get_statistics() + { + $sql = 'SELECT idea_status FROM ' . $this->table_ideas; + $result = $this->db->sql_query($sql); + $rows = $this->db->sql_fetchrowset($result); + $this->db->sql_freeresult($result); + + $total = count($rows); + $status_counts = $total ? array_count_values(array_column($rows, 'idea_status')) : []; + + return [ + 'total' => $total, + 'implemented' => $status_counts[ext::$statuses['IMPLEMENTED']] ?? 0, + 'in_progress' => $status_counts[ext::$statuses['IN_PROGRESS']] ?? 0, + 'duplicate' => $status_counts[ext::$statuses['DUPLICATE']] ?? 0, + 'invalid' => $status_counts[ext::$statuses['INVALID']] ?? 0, + 'new' => $status_counts[ext::$statuses['NEW']] ?? 0, + ]; + } } diff --git a/language/en/common.php b/language/en/common.php index d06b64e..11be312 100644 --- a/language/en/common.php +++ b/language/en/common.php @@ -101,6 +101,7 @@ 1 => '%s point.', 2 => '%s points.', ], + 'TOTAL_POSTED_IDEAS' => 'Total ideas posted', 'UPDATED_VOTE' => 'Successfully updated vote!', diff --git a/styles/prosilver/template/index_body.html b/styles/prosilver/template/index_body.html index 05403f5..240a16d 100644 --- a/styles/prosilver/template/index_body.html +++ b/styles/prosilver/template/index_body.html @@ -40,6 +40,11 @@

{{ lang('IDEAS_TITLE') }}

{# IN PROGRESS IDEAS #} {{ _self.ideas_section(lang('IN_PROGRESS_IDEAS'), in_progress_ideas, U_VIEW_IN_PROGRESS, 'fa-clock-o', lang('VIEW_IN_PROGRESS')) }} -

+
+

{{ lang('STATISTICS') }}

+

+ {{ lang('TOTAL_POSTED_IDEAS') }} {{ STATISTICS.total }} • {{ lang('LIST_IMPLEMENTED') }} {{ STATISTICS.implemented }} • {{ lang('LIST_IN_PROGRESS') }} {{ STATISTICS.in_progress }} +

+
{% include 'overall_footer.html' %} diff --git a/tests/ideas/get_statistics_test.php b/tests/ideas/get_statistics_test.php new file mode 100644 index 0000000..c551b78 --- /dev/null +++ b/tests/ideas/get_statistics_test.php @@ -0,0 +1,28 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + */ + +namespace phpbb\ideas\tests\ideas; + +class get_statistics_test extends ideas_base +{ + public function test_get_statistics() + { + $object = $this->get_ideas_object(); + + $stats = $object->get_statistics(); + + self::assertEquals(7, $stats['total']); + self::assertEquals(1, $stats['implemented']); + self::assertEquals(1, $stats['in_progress']); + self::assertEquals(0, $stats['duplicate']); + self::assertEquals(0, $stats['invalid']); + self::assertEquals(5, $stats['new']); + } +} From a460e0d7fa9af655cbe0b37cab09823668b2c4b8 Mon Sep 17 00:00:00 2001 From: Matt Friedman Date: Thu, 13 Nov 2025 07:11:14 -0800 Subject: [PATCH 2/4] Test --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2dff33c..e572560 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,7 @@ on: jobs: call-tests: name: Extension tests - uses: phpbb-extensions/test-framework/.github/workflows/tests.yml@3.3.x + uses: iMattPro/test-framework/.github/workflows/tests.yml@epv with: EXTNAME: phpbb/ideas # Your extension vendor/package name CODECOV: 1 # Run code coverage via codecov? 1 or 0 From 9e34db78bdb76da210675e2701d39b6a54cd03f2 Mon Sep 17 00:00:00 2001 From: Matt Friedman Date: Thu, 13 Nov 2025 07:52:31 -0800 Subject: [PATCH 3/4] Revert "Test" This reverts commit a460e0d7fa9af655cbe0b37cab09823668b2c4b8. --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e572560..2dff33c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,7 @@ on: jobs: call-tests: name: Extension tests - uses: iMattPro/test-framework/.github/workflows/tests.yml@epv + uses: phpbb-extensions/test-framework/.github/workflows/tests.yml@3.3.x with: EXTNAME: phpbb/ideas # Your extension vendor/package name CODECOV: 1 # Run code coverage via codecov? 1 or 0 From 3cf004cd19c60a04c10bd68a8c1aa8a9b0ebcb71 Mon Sep 17 00:00:00 2001 From: Matt Friedman Date: Fri, 14 Nov 2025 07:46:12 -0800 Subject: [PATCH 4/4] Optimize statistics getting by using SQL over PHP --- factory/ideas.php | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/factory/ideas.php b/factory/ideas.php index 6fd2189..e5efe9d 100644 --- a/factory/ideas.php +++ b/factory/ideas.php @@ -298,27 +298,33 @@ public function get_idea_count() } /** - * Get total ideas statistics + * Get statistics - counts of total ideas and of each status type * * @return array */ public function get_statistics() { - $sql = 'SELECT idea_status FROM ' . $this->table_ideas; + // the CASE/WHEN SQL approach is better for performance than processing in PHP + $sql = 'SELECT + COUNT(*) as total, + SUM(CASE WHEN idea_status = ' . (int) ext::$statuses['IMPLEMENTED'] . ' THEN 1 ELSE 0 END) as implemented, + SUM(CASE WHEN idea_status = ' . (int) ext::$statuses['IN_PROGRESS'] . ' THEN 1 ELSE 0 END) as in_progress, + SUM(CASE WHEN idea_status = ' . (int) ext::$statuses['DUPLICATE'] . ' THEN 1 ELSE 0 END) as duplicate, + SUM(CASE WHEN idea_status = ' . (int) ext::$statuses['INVALID'] . ' THEN 1 ELSE 0 END) as invalid, + SUM(CASE WHEN idea_status = ' . (int) ext::$statuses['NEW'] . ' THEN 1 ELSE 0 END) as new + FROM ' . $this->table_ideas; + $result = $this->db->sql_query($sql); - $rows = $this->db->sql_fetchrowset($result); + $row = $this->db->sql_fetchrow($result); $this->db->sql_freeresult($result); - $total = count($rows); - $status_counts = $total ? array_count_values(array_column($rows, 'idea_status')) : []; - return [ - 'total' => $total, - 'implemented' => $status_counts[ext::$statuses['IMPLEMENTED']] ?? 0, - 'in_progress' => $status_counts[ext::$statuses['IN_PROGRESS']] ?? 0, - 'duplicate' => $status_counts[ext::$statuses['DUPLICATE']] ?? 0, - 'invalid' => $status_counts[ext::$statuses['INVALID']] ?? 0, - 'new' => $status_counts[ext::$statuses['NEW']] ?? 0, + 'total' => (int) $row['total'], + 'implemented' => (int) $row['implemented'], + 'in_progress' => (int) $row['in_progress'], + 'duplicate' => (int) $row['duplicate'], + 'invalid' => (int) $row['invalid'], + 'new' => (int) $row['new'], ]; } }