Not sure if I will able to help you, since i don't know the DB structure, but from personal experience a lot of heavy reporting can easily be done with queries.
Here is an idea for an approach. Start with generating a query that replicate one row from your report. For example For "Law 1", try to get all computed values for the departments you need. First start with hard-coded columns for few departments, doesn't need to be all, 1,2,3 is enough.
Try to write a query to pull the info you need. For the computed values i would recommend to go with sub queries. Not sure how is your DB structure, so joins might get u in trouble in some cases. This will look something like this (please don't mind if the query not correct just trying to give an idea):
SELECT
law.name,
(SELECT SUM(department.column_X) FROM department WHERE department.id = 1) AS "Department 1",
(SELECT SUM(department.column_X) FROM department WHERE department.id = 2) AS "Department 2",
(SELECT SUM(department.column_X) FROM department WHERE department.id = 3) AS "Department 3"
FROM law
If you can replicate a simple query like this to pull data like in your report, you are alomst done.
Next you just need to dynamically create the final query. First you will need to create a query builder, so you can build your query dynamically.
And you can simply do this by, first, getting all the departments with a separate query, like from your model.
$departments = Department::all();
Or apply any filters if you need. Easy
Then, you will foreach the departments and just add selects with the sub-query that you've build at the very begging.
$departments = Department::all();
$query = DB::table('law')->select('law.name');
foreach ($departments as $department) {
$query->addSelect("department_{$department->id}", function ($query) use ($department) {
$query->selectRaw('SUM(department.column_x)')
->from('department')
->where('department.id, '=', $department->id);
});
}
$query->get():
You will end up with just 2 queries. Hope this helps.