0
0

More than 1 year has passed since last update.

両方(UNION等で結合が要)対応する場合

Last updated at Posted at 2023-07-17

前回で実績のみ対応した。(誤差を求め、特定の値(filter)を取得する)
今回は両方(実績、予算)対応する。
その場合であるが、グループ化を3つの変数に対し行うことになりネストが深くなる。
今回はコレクション型でforeachでも扱えるのでそれを使用する。

モデル

LaravelでDBファザードのDB::selectで対応と同じ。

コントローラ

ProjectWorkController.php
<?php

namespace App\Http\Controllers;

use App\Models\Models\ProjectWork as ModelsProjectWork;
use Illuminate\Http\Request;
use App\Models\Models\ProjectWork;
use Illuminate\Support\Facades\DB;

class ProjectWorkController extends Controller
{
    public function index()
    {

        $results = ProjectWork::getWorkHoursPerProjectInAMonth('2023-06-01', '2023-08-31');

        $results = collect($results)->groupBy(['employee_id', 'month', 'budget_actual_flag']);
        foreach ($results as $employeeId => $months) {
            foreach ($months as $month => $flags) {
                foreach ($flags as $flag => $data) {
                    $totalRatio = 0;

                    // 各 budget_actual_flag の値(0または1)について、ratio の合計を計算します。
                    foreach ($data as $datum) {
                        $totalRatio += $datum->ratio;
                    }

                    echo "Before adjustment, total ratio for employee {$employeeId}, month {$month}, flag {$flag}: " . number_format($totalRatio, 2) . "\n";

                    // 各 budget_actual_flag の値(0または1)について、ratio を調整します。
                    foreach ($data as $index => $datum) {
                        // Round to 2 decimal places after calculating the new ratio
                        $datum->ratio = round($datum->ratio / $totalRatio, 2);
                        $data[$index] = $datum;
                    }

                    $totalRatio = 0;
                    foreach ($data as $datum) {
                        $totalRatio += $datum->ratio;
                    }

                    if ($totalRatio !== 1.0) {
                        $data[count($data) - 1]->ratio += round(1 - $totalRatio, 2);
                    }

                    $totalRatio = 0;
                    foreach ($data as $datum) {
                        $totalRatio += $datum->ratio;
                    }

                    echo "After adjustment, total ratio for employee {$employeeId}, month {$month}, flag {$flag}: " . number_format($totalRatio, 2) . "\n";

                    $flags[$flag] = $data;  // 参照を使用せずにデータを直接変更
                }
                $months[$month] = $flags;  // 参照を使用せずにデータを直接変更
            }
            $results[$employeeId] = $months;  // 参照を使用せずにデータを直接変更
        }


        dd($results);
    }
}

collect($results)->groupBy(['employee_id', 'month', 'budget_actual_flag'])
にて、'employee_id', 'month', 'budget_actual_flag'をグループ化し、比率を再計算することになる。
その操作をする場合、mapメソッドでratioにアクセスすることになるが、ネストが深くなり可読性が悪くなる。
よって、今回はコレクション型をPHPの連想配列のようにforeachで処理している。
コレクション型のmapメソッドを使えば新しいコレクションを返すが、今回は直接データを書き換えて対応している。(ただ、今回はオブジェクトのプロパティにアクセスしているので直接$resultを書き換えており、$flags[$flag] = $data等3つの記載は冗長になる。)

(結果例)

Illuminate\Support\Collection {#654 ▼ // app/Http/Controllers/ProjectWorkController.php:435
  #items: array:22 [▶
    "EMP001" => Illuminate\Support\Collection {#662 ▶
      #items: array:3 [▶
        202306 => Illuminate\Support\Collection {#666 ▶
          #items: array:2 [▶
            0 => Illuminate\Support\Collection {#664 ▶
              #items: array:4 [▶
                0 => {#297 ▶
                  +"employee_id": "EMP001"
                  +"month": "202306"
                  +"project_code": "PRJ001"
                  +"budget_actual_flag": 0
                  +"total_work_hours": "8.00"
                  +"ratio": 0.33
                }
                1 => {#299 ▶
                  +"employee_id": "EMP001"
                  +"month": "202306"
                  +"project_code": "PRJ002"
                  +"budget_actual_flag": 0
                  +"total_work_hours": "7.00"
                  +"ratio": 0.29
                }
                2 => {#300 ▶
                  +"employee_id": "EMP001"
                  +"month": "202306"
                  +"project_code": "PRJ003"
                  +"budget_actual_flag": 0
                  +"total_work_hours": "7.00"
                  +"ratio": 0.29
                }
                3 => {#301 ▶
                  +"employee_id": "EMP001"
                  +"month": "202306"
                  +"project_code": "PRJ004"
                  +"budget_actual_flag": 0
                  +"total_work_hours": "2.00"
                  +"ratio": 0.09
                }
              ]

特定プロジェクトのみ取得

先ほどに対し、以下コードを追加。
ネストが深くなるが今回はmapメソッドを使用した。
対象データがない場合、何もない配列ができるので、isNotEmpty()で返している。

        $filterResults = $results->map(function ($months) {
            return $months->map(function ($flags) {
                return $flags->map(function ($data) {
                    return $data->filter(function ($data_s) {
                        return $data_s->project_code == 'PRJ0001';
                    });
                })->filter(function ($data) {
                    return $data->isNotEmpty();
                });
            })->filter(function ($flags) {
                return $flags->isNotEmpty();
            });
        })->filter(function ($months) {
            return $months->isNotEmpty();
        });

        dd($filterResults);

(結果例)

Illuminate\Support\Collection {#650 ▼ // app/Http/Controllers/ProjectWorkController.php:463
  #items: array:22 [▶
    "EMP001" => Illuminate\Support\Collection {#647 ▶
      #items: array:3 [▶
        202306 => Illuminate\Support\Collection {#646 ▶
          #items: array:2 [▶
            0 => Illuminate\Support\Collection {#645 ▶
              #items: array:1 [▶
                0 => {#297 ▶
                  +"employee_id": "EMP001"
                  +"month": "202306"
                  +"project_code": "PRJ001"
                  +"budget_actual_flag": 0
                  +"total_work_hours": "8.00"
                  +"ratio": 0.33
                }
              ]
              #escapeWhenCastingToString: false
            }
            1 => Illuminate\Support\Collection {#644 ▶
              #items: array:1 [▶
                0 => {#302 ▶
                  +"employee_id": "EMP001"
                  +"month": "202306"
                  +"project_code": "PRJ001"
                  +"budget_actual_flag": 1
                  +"total_work_hours": "9.00"
                  +"ratio": 0.41
                }
              ]
              #escapeWhenCastingToString: false
            }
          ]
          #escapeWhenCastingToString: false
        }
        202307 => Illuminate\Support\Collection {#643 ▶
          #items: array:2 [▶
            0 => Illuminate\Support\Collection {#642 ▶
              #items: array:1 [▶
                0 => {#306 ▶
                  +"employee_id": "EMP001"
                  +"month": "202307"
                  +"project_code": "PRJ001"
                  +"budget_actual_flag": 0
                  +"total_work_hours": "10.00"
                  +"ratio": 0.53
                }
              ]
              #escapeWhenCastingToString: false
            }
            1 => Illuminate\Support\Collection {#641 ▶
              #items: array:1 [▶
                0 => {#308 ▶
                  +"employee_id": "EMP001"
                  +"month": "202307"
                  +"project_code": "PRJ001"
                  +"budget_actual_flag": 1
                  +"total_work_hours": "4.00"
                  +"ratio": 0.2
                }
              ]
              #escapeWhenCastingToString: false
            }
          ]
          #escapeWhenCastingToString: false
        }

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0