星評価を作成する(Laravelのfor文を使用)

書籍の評価一覧ページを作成するにあたり、for文を使って星評価を作成した。

# 作業内容

以下のように表示されている評価欄の数字を

| 本の題名 | 本の作者 | 評価 |
| --- | --- | --- |
| ノルウェイの森 | 村上春樹 | 4 |
| 神秘の島 | ヴェルヌ | 5 |
|  | 〜 |  |

 　　　　　　　　　　↓

| 本の題名 | 本の作者 | 評価 |
| --- | --- | --- |
| ノルウェイの森 | 村上春樹 | ⭐️⭐️⭐️⭐️☆ |
| 神秘の島 | ヴェルヌ | ⭐️⭐️⭐️⭐️⭐️ |
|  | 〜 |  |

上記のように⭐️を使った表示に変更する。
（5段階評価）

# この記事の前提

**星評価を作成するための数字を保存しているカラムがあること。**

テーブルの構造は下記(countカラムを使用)

```sql
Create Table: CREATE TABLE evaluations (
id bigint unsigned NOT NULL AUTO_INCREMENT,
created_at timestamp NULL DEFAULT NULL,
updated_at timestamp NULL DEFAULT NULL,
〜
count tinyint NOT NULL,
```

# 以下、編集したファイルの中身

サービスクラス

```php
<?php

namespace App\Services;

use App\Models\Evaluation;

public function evaluate(Evaluation $evaluation)
    {
        $rating = $evaluation->count;
        
        $stars = '';
        for ($i = 0; $i < 5; $i++) {
            if ($i < $rating) {
                $stars .= '★';
            } else {
                $stars .= '☆';
        }
        return $stars;
    }
```

コントローラー

```php
class EvaluationController extends Controller
{
    private $evaluationService;

    public function __construct(EvaluationService $evaluationService)
    {
        $this->evaluationService = $evaluationService;
    }

    public function index($id)
    {
        $login_user = Auth::user();
        $book = Book::find($id);
        $evaluations = $book->evaluations()->with('user')->get();
        foreach ($evaluations as $evaluation) {
            $evaluation->stars = $this->evaluationService->evaluate($evaluation);
        }
        return view('evaluation.index', compact('book', 'evaluations', 'login_user'));
    }
```

ブレードファイル

```php
<tbody>
	@foreach ($evaluations as $evaluation)
	  <tr>
	    <td>{{ $evaluation->user->name }}</td>
	    <td>{{ $evaluation->count }}</td>
	    <td>{{ $evaluation->stars }}</td>
	    <td><a href="{{ route('evaluation.show', ['id' => $evaluation->id]) }}">{{ $evaluation->title }}</a></td>
	  </tr>
	 @endforeach
</tbody>
```

# 処理の流れ

**サービスクラス**

```php
public function evaluate(Evaluation $evaluation)
    {
        $rating = $evaluation->count;
        
        $stars = '';
        for ($i = 0; $i < 5; $i++) {
            if ($i < $rating) {
                $stars .= '★';
            } else {
                $stars .= '☆';
        }
        return $stars;
    }
```

count（例えば3）を受け取り、そのcountの数だけ星（⭐️⭐️⭐️）を生成し、残りは空の星で埋める（⭐️⭐️⭐️☆☆）という処理。

$i < 5; のため、5回ループすると終了し、最終的に5段階評価となる。

最終的に戻り値として$starsが返される。

.=は連結演算子であり、文字列である星を繋げて表示するために使用している。

https://www.php.net/manual/ja/language.operators.string.php

**コントローラー**


コンストラクタを使用してサービスクラスを扱えるようにする。

```php
$evaluations = $book->evaluations()->with('user')->get();
   foreach ($evaluations as $evaluation) {
       $evaluation->stars = $this->evaluationService->evaluate($evaluation);
   }
```

$evaluationsに本に関する情報を全て格納し、foreachで回している。
サービスクラスを介することで数字が星に変換される。

**最後にビュー**

```php
@foreach ($evaluations as $evaluation)
	  <tr>
	    <td>{{ $evaluation->user->name }}</td>
	    <td>{{ $evaluation->count }}</td>
	    <td>{{ $evaluation->stars }}</td>
	    <td><a href="{{ route('evaluation.show', ['id' => $evaluation->id]) }}">{{ $evaluation->title }}</a></td>
	  </tr>
@endforeach
```

上記のように記述することでブラウザ上に表示することができる。

このような処理はfor文以外でもいろいろなやり方がある模様。