From 4efa1215cfd1bc41b4da5ce73446f1c8927e3d90 Mon Sep 17 00:00:00 2001 From: gakigaki Date: Wed, 4 Jun 2025 02:28:10 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E5=8D=98=E8=AA=9E=E6=95=B0?= =?UTF-8?q?=E3=81=A8=E5=AD=97=E6=95=B0=E3=81=AE=E8=A1=A8=E7=A4=BA=E6=A9=9F?= =?UTF-8?q?=E8=83=BD=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - レポートに単語数と字数のオプションを追加 - LearningtasksUsersStatusesに単語数と字数のアクセサを実装 - CSVデータプロバイダーに単語数と字数のカラムを追加 - テストを追加して単語数と字数の計算を確認 --- app/Enums/LearningtaskUseFunction.php | 4 ++ .../LearningtasksUsersStatuses.php | 19 +++++++ .../DataProviders/ReportCsvDataProvider.php | 2 + .../LearningtaskReportColumnDefinition.php | 8 +++ ...learningtasks_edit_learningtasks.blade.php | 13 ++++- .../learningtasks_edit_report.blade.php | 13 ++++- ...learningtasks_show_report_status.blade.php | 23 +++++++- .../LearningtasksUsersStatusesTest.php | 54 +++++++++++++++++++ .../ReportCsvDataProviderTest.php | 53 ++++++++++++++++++ 9 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 tests/Unit/Models/User/Learningtasks/LearningtasksUsersStatusesTest.php diff --git a/app/Enums/LearningtaskUseFunction.php b/app/Enums/LearningtaskUseFunction.php index ceace37d0..f68242616 100644 --- a/app/Enums/LearningtaskUseFunction.php +++ b/app/Enums/LearningtaskUseFunction.php @@ -43,6 +43,8 @@ final class LearningtaskUseFunction extends EnumsBase const use_report_reference_mail = 'use_'.self::report.'_reference_mail'; // [表示方法] const use_report_status_collapse = 'use_'.self::report.'_status_collapse'; + const use_report_show_word_count = 'use_'.self::report.'_show_word_count'; + const use_report_show_char_count = 'use_'.self::report.'_show_char_count'; // --- 試験設定 // [利用する試験提出機能] @@ -110,6 +112,8 @@ final class LearningtaskUseFunction extends EnumsBase self::use_report_reference_mail => 'メール送信(受講者宛)', // 表示方法 self::use_report_status_collapse => '履歴を開閉する', + self::use_report_show_word_count => '文字数を表示する', + self::use_report_show_char_count => '字数を表示する', // --- 試験設定 // 利用する試験提出機能 self::use_examination => '提出', diff --git a/app/Models/User/Learningtasks/LearningtasksUsersStatuses.php b/app/Models/User/Learningtasks/LearningtasksUsersStatuses.php index c551d96ec..430cd56b5 100644 --- a/app/Models/User/Learningtasks/LearningtasksUsersStatuses.php +++ b/app/Models/User/Learningtasks/LearningtasksUsersStatuses.php @@ -192,4 +192,23 @@ public function upload() // withDefault() を指定しておくことで、Uploads がないときに空のオブジェクトが返ってくるので、null po 防止。 return $this->hasOne(Uploads::class, 'id', 'upload_id')->withDefault(); } + + /** + * 単語数を取得する + */ + public function getWordCountAttribute() + { + // マルチバイト文字などは適切な値を取得できない + // 必要になれば形態素解析などを行う必要がある + return $this->comment ? str_word_count($this->comment) : 0; + } + + /** + * 字数を取得する + * 文字数は、全角文字も半角文字も1文字としてカウントする。 + */ + public function getCharCountAttribute() + { + return $this->comment ? mb_strlen($this->comment) : 0; + } } diff --git a/app/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProvider.php b/app/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProvider.php index 32c0cc555..d1e513c35 100644 --- a/app/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProvider.php +++ b/app/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProvider.php @@ -171,6 +171,8 @@ private function getColumnDataGenerators( }, '評価' => fn() => optional($last_evaluation)->grade, '評価コメント' => fn() => optional($last_evaluation)->comment, + '単語数' => fn() => optional($last_submission)->word_count, + '字数' => fn() => optional($last_submission)->char_count, ]; } } diff --git a/app/Plugins/User/Learningtasks/Services/LearningtaskReportColumnDefinition.php b/app/Plugins/User/Learningtasks/Services/LearningtaskReportColumnDefinition.php index 4fadcc79f..5ee9bc09c 100644 --- a/app/Plugins/User/Learningtasks/Services/LearningtaskReportColumnDefinition.php +++ b/app/Plugins/User/Learningtasks/Services/LearningtaskReportColumnDefinition.php @@ -28,6 +28,8 @@ class LearningtaskReportColumnDefinition implements ColumnDefinitionInterface // 'ファイルURL' => 'file_url', '評価' => 'grade', '評価コメント' => 'comment', + '単語数' => 'word_count', + '字数' => 'char_count', ]; /** @@ -58,6 +60,12 @@ public function getHeaders(): array if ($this->setting_checker->isEnabled(LearningtaskUseFunction::use_report_comment)) { $header_columns[] = '本文'; } + if ($this->setting_checker->isEnabled(LearningtaskUseFunction::use_report_show_word_count)) { + $header_columns[] = '単語数'; + } + if ($this->setting_checker->isEnabled(LearningtaskUseFunction::use_report_show_char_count)) { + $header_columns[] = '字数'; + } if ($this->setting_checker->isEnabled(LearningtaskUseFunction::use_report_file)) { $header_columns[] = 'ファイルURL'; } diff --git a/resources/views/plugins/user/learningtasks/default/learningtasks_edit_learningtasks.blade.php b/resources/views/plugins/user/learningtasks/default/learningtasks_edit_learningtasks.blade.php index 175c5d190..ee62e8abd 100644 --- a/resources/views/plugins/user/learningtasks/default/learningtasks_edit_learningtasks.blade.php +++ b/resources/views/plugins/user/learningtasks/default/learningtasks_edit_learningtasks.blade.php @@ -340,11 +340,20 @@ class="custom-control-input"
-
-
+
+
getFunction('use_report_status_collapse')) == 'on') checked=checked @endif>
+
+ getFunction('use_report_show_word_count')) == 'on') checked=checked @endif> + +
+
+ getFunction('use_report_show_char_count')) == 'on') checked=checked @endif> + +
+ 単語数の表示は、日本語などのマルチバイト文字に対応していません。
diff --git a/resources/views/plugins/user/learningtasks/default/learningtasks_edit_report.blade.php b/resources/views/plugins/user/learningtasks/default/learningtasks_edit_report.blade.php index a30fbdf19..fa3e615c7 100644 --- a/resources/views/plugins/user/learningtasks/default/learningtasks_edit_report.blade.php +++ b/resources/views/plugins/user/learningtasks/default/learningtasks_edit_report.blade.php @@ -231,11 +231,20 @@ class="custom-control-input"
-
-
+
+
getFunction('use_report_status_collapse', true)) == 'on') checked=checked @endif>
+
+ getFunction('use_report_show_word_count', true)) == 'on') checked=checked @endif> + +
+
+ getFunction('use_report_show_char_count', true)) == 'on') checked=checked @endif> + +
+ 単語数の表示は、日本語などのマルチバイト文字に対応していません。
diff --git a/resources/views/plugins/user/learningtasks/default/learningtasks_show_report_status.blade.php b/resources/views/plugins/user/learningtasks/default/learningtasks_show_report_status.blade.php index 9fe8ae583..9bb9f69e9 100644 --- a/resources/views/plugins/user/learningtasks/default/learningtasks_show_report_status.blade.php +++ b/resources/views/plugins/user/learningtasks/default/learningtasks_show_report_status.blade.php @@ -31,7 +31,28 @@ @if ($tool->isUseFunction($user_status->task_status, 'comment')) コメント - {!!nl2br(e($user_status->comment))!!} + {!!nl2br(e($user_status->comment))!!} + {{-- 文字数、単語数の表示 --}} + @php + $should_show_word_count = $tool->isUseFunction($user_status->task_status, 'show_word_count'); + $should_show_char_count = $tool->isUseFunction($user_status->task_status, 'show_char_count'); + $word_count = $user_status->word_count; + $char_count = $user_status->char_count; + @endphp + @if ($should_show_word_count || $should_show_char_count) +
+ @if ($should_show_word_count) + {{ $word_count }}単語 + @endif + @if ($should_show_word_count && $should_show_char_count) + / + @endif + @if ($should_show_char_count) + {{ $char_count }}文字 + @endif +
+ @endif + @endif diff --git a/tests/Unit/Models/User/Learningtasks/LearningtasksUsersStatusesTest.php b/tests/Unit/Models/User/Learningtasks/LearningtasksUsersStatusesTest.php new file mode 100644 index 000000000..ee853f0d4 --- /dev/null +++ b/tests/Unit/Models/User/Learningtasks/LearningtasksUsersStatusesTest.php @@ -0,0 +1,54 @@ + null]); + $this->assertSame(0, $model->word_count); + $model = new LearningtasksUsersStatuses(['comment' => '']); + $this->assertSame(0, $model->word_count); + } + + /** + * commentの内容に応じてword_countが正しい値を返すことをテスト + */ + public function testWordCountReturnsExpectedValue(): void + { + $model = new LearningtasksUsersStatuses(['comment' => 'This is a test']); + $this->assertSame(4, $model->word_count); + } + + /** + * commentがnullまたは空文字の場合、char_countは0を返すことをテスト + */ + public function testCharCountIsZeroWhenCommentIsNullOrEmpty(): void + { + $model = new LearningtasksUsersStatuses(['comment' => null]); + $this->assertSame(0, $model->char_count); + $model = new LearningtasksUsersStatuses(['comment' => '']); + $this->assertSame(0, $model->char_count); + } + + /** + * commentの内容に応じてchar_countが正しい値を返すことをテスト + */ + public function testCharCountReturnsExpectedValue(): void + { + $model = new LearningtasksUsersStatuses(['comment' => 'abc']); + $this->assertSame(3, $model->char_count); + $model = new LearningtasksUsersStatuses(['comment' => 'テストword']); + $this->assertSame(7, $model->char_count); + } +} diff --git a/tests/Unit/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProviderTest.php b/tests/Unit/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProviderTest.php index b244eef83..12e412743 100644 --- a/tests/Unit/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProviderTest.php +++ b/tests/Unit/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProviderTest.php @@ -277,4 +277,57 @@ public function getRowsYieldsDataWithEmptyFieldsWhenNoStatuses(): void ]; $this->assertEquals($expected_row_data, $result_rows_array[0], '提出/評価がない学生のデータが期待通りであること'); } + + /** + * 単語数・字数カラムが有効な場合に正しい値が出力されるテスト(カスタムアクセサ対応) + * @test + * @covers ::getRows + * @group learningtasks + * @group learningtasks-dataprovider + */ + public function getRowsYieldsWordAndCharCountColumns(): void + { + // Arrange + $student = User::factory()->create(['userid' => 's003', 'name' => '学生 丙']); + $submission_comment = 'word テスト 123'; // 半角2単語+全角1単語+数字1単語 → str_word_count=3, mb_strlen=11 + $submission_created_at_str = now()->subHour()->toDateTimeString(); + $submission = LearningtasksUsersStatuses::factory()->create([ + 'post_id' => $this->post->id, 'user_id' => $student->id, 'task_status' => 1, + 'comment' => $submission_comment, 'upload_id' => 888, 'created_at' => $submission_created_at_str, + ]); + // 評価データも追加(値は使わない) + LearningtasksUsersStatuses::factory()->create([ + 'post_id' => $this->post->id, 'user_id' => $student->id, 'task_status' => 2, + 'grade' => '優', 'comment' => '評価コメント', + ]); + + // ヘッダーに単語数・字数を含める + $headers = ['ログインID', 'ユーザ名', '提出日時', '提出回数', '単語数', '字数']; + $this->mock_column_definition->shouldReceive('getHeaders')->once()->andReturn($headers); + $this->mock_user_repository->shouldReceive('getStudents') + ->with($this->post, $this->page) + ->once() + ->andReturn(new EloquentCollection([$student])); + + // Act + $result_iterable = $this->data_provider->getRows( + $this->mock_column_definition, + $this->post, + $this->page, + $this->site_url + ); + $result_rows_array = iterator_to_array($result_iterable); + + // Assert + $this->assertCount(1, $result_rows_array, '学生1名分のデータが yield されるべき'); + $expected_row = [ + $student->userid, + $student->name, + $submission_created_at_str, + '1', // 提出回数 + str_word_count($submission_comment), // 単語数(PHPのstr_word_count仕様) + mb_strlen($submission_comment), // 字数(全角・半角問わず) + ]; + $this->assertEquals($expected_row, $result_rows_array[0], '単語数・字数カラムの値が正しく出力されること'); + } } From 8bf6aecc8ab4756c54bd8e6dc69e9861b8d36c3f Mon Sep 17 00:00:00 2001 From: gakigaki Date: Wed, 4 Jun 2025 02:41:42 +0900 Subject: [PATCH 2/2] =?UTF-8?q?del:=20=E4=B8=8D=E8=A6=81=E3=81=AA=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Learningtasks/DataProviders/ReportCsvDataProviderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProviderTest.php b/tests/Unit/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProviderTest.php index 12e412743..db68f98c8 100644 --- a/tests/Unit/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProviderTest.php +++ b/tests/Unit/Plugins/User/Learningtasks/DataProviders/ReportCsvDataProviderTest.php @@ -279,7 +279,7 @@ public function getRowsYieldsDataWithEmptyFieldsWhenNoStatuses(): void } /** - * 単語数・字数カラムが有効な場合に正しい値が出力されるテスト(カスタムアクセサ対応) + * 単語数・字数カラムが有効な場合に正しい値が出力されるテスト * @test * @covers ::getRows * @group learningtasks