Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
n/a
0 / 0
n/a
0 / 0
CRAP
n/a
0 / 0
StatsController
n/a
0 / 0
n/a
0 / 0
12
n/a
0 / 0
 viewStatsByBrand
n/a
0 / 0
n/a
0 / 0
2
 exportByBrandCsv
n/a
0 / 0
n/a
0 / 0
3
 viewByQuestion
n/a
0 / 0
n/a
0 / 0
2
 exportByQuestionCsv
n/a
0 / 0
n/a
0 / 0
2
 answersByDays
n/a
0 / 0
n/a
0 / 0
3
1<?php
2
3namespace App\Http\Controllers;
4
5use App\Http\Requests\StatsByBrandRequest;
6use App\Http\Requests\StatsByQuestionRequest;
7use App\Models\Brand;
8use App\Models\BrandStat;
9use App\Models\CustomerAnswer;
10use App\Models\Question;
11use Illuminate\Support\Carbon;
12use Illuminate\Support\Collection;
13use Illuminate\Support\Facades\Schema;
14use League\Csv\Writer;
15
16/**
17 * @codeCoverageIgnore
18 */
19class StatsController extends Controller
20{
21    /**
22     * Shows stats by brand
23     *
24     * @param \App\Http\Requests\StatsByBrandRequest $request
25     * @return \Illuminate\Http\Response
26     */
27    public function viewStatsByBrand(StatsByBrandRequest $request)
28    {
29        $stats = null;
30        if ($request->post()) {
31            $stats = BrandStat::whereDate('created_at', '>=', $request->start)
32                ->whereDate('created_at', '<=', $request->end)
33                ->whereBrandId($request->brand)->get();
34        }
35        return view('stats.view-stats-by-brands', \compact('stats'));
36    }
37
38    /**
39     * Exports stats by brand as a csv file
40     *
41     * @param \App\Http\Requests\StatsByBrandRequest $request
42     * @return \Illuminate\Http\Response
43     */
44    public function exportByBrandCsv(StatsByBrandRequest $request)
45    {
46        $brand = Brand::findOrFail($request->brand);
47        $stats = BrandStat::with('brand')->whereDate('created_at', '>=', $request->start)
48            ->whereDate('created_at', '<=', $request->end)
49            ->whereBrandId($request->brand)->get();
50
51        $columns = collect(Schema::getColumnListing((new BrandStat())->getTable()))
52            ->filter(function ($value) {
53                return !in_array($value, ['created_at', 'brand_id']);
54            })->all();
55
56        $header = '"date";"marque";' . implode(';', $columns);
57
58        $w = Writer::createFromString($header . PHP_EOL);
59        $w->setDelimiter(';');
60        $w->setEnclosure('"');
61        $w->setOutputBOM(Writer::BOM_UTF8);
62
63        foreach ($stats as $stat) {
64            $cols = [
65                $stat->created_at->format('Y-m-d'),
66                $stat->brand->name
67            ];
68            foreach ($columns as $colname) {
69                $cols[] = $stat->{$colname};
70            }
71            $w->insertOne($cols);
72        }
73        return response((string)$w, 200, [
74            'Content-Encoding' => 'none',
75            'Content-Type' => 'text/csv; charset=UTF-8',
76            // phpcs:ignore Generic.Files.LineLength.TooLong
77            'Content-Disposition' => "attachment; filename=\"Statistiques du $request->start au $request->end pour $brand->name.csv\"",
78            'Content-Description' => 'File Transfer',
79        ]);
80    }
81
82    /**
83     * Views stats for a specific question
84     *
85     * @param \App\Http\Requests\StatsByQuestionRequest $request
86     * @return \Illuminate\Http\Response
87     */
88    public function viewByQuestion(StatsByQuestionRequest $request)
89    {
90        $question      = null;
91        $answers       = null;
92        $answersByDays = null;
93        if ($request->post()) {
94            $question = Question::findOrFail($request->question);
95            $answers  = $question->answers;
96            $start    = Carbon::parse($request->start);
97            $end      = Carbon::parse($request->end);
98
99            $answersByDays = $this->answersByDays($answers, $start, $end);
100        }
101
102        return view('stats.view-stats-by-questions', \compact('question', 'answers', 'answersByDays'));
103    }
104
105    /**
106     * Exports stats for a specific question as csv
107     *
108     * @param \App\Http\Requests\StatsByQuestionRequest $request
109     * @return \Illuminate\Http\Response
110     */
111    public function exportByQuestionCsv(StatsByQuestionRequest $request)
112    {
113        $question = Question::findOrFail($request->question);
114        $answers  = $question->answers;
115        $start    = Carbon::parse($request->start);
116        $end      = Carbon::parse($request->end);
117
118        $answersByDays = $this->answersByDays($answers, $start, $end);
119
120        $header = '"date";' . implode(';', $answers->map(function ($answer) {
121            return "\"$answer->answer\"";
122        })->all());
123
124        $w = Writer::createFromString($header . PHP_EOL);
125        $w->setDelimiter(';');
126        $w->setEnclosure('"');
127        $w->setOutputBOM(Writer::BOM_UTF8);
128
129        foreach ($answersByDays as $day => $dayAnswers) {
130            $w->insertOne(array_merge(
131                [
132                    $day
133                ],
134                $dayAnswers->values()->all()
135            ));
136        }
137        return response((string)$w, 200, [
138            'Content-Encoding' => 'none',
139            'Content-Type' => 'text/csv; charset=UTF-8',
140            // phpcs:ignore Generic.Files.LineLength.TooLong
141            'Content-Disposition' => "attachment; filename=\"Statistiques du $request->start au $request->end pour $question->question.csv\"",
142            'Content-Description' => 'File Transfer',
143        ]);
144    }
145
146    /**
147     * Makes a collection of total users answers by day
148     *
149     * @param \Illuminate\Support\Collection $answers A collection of Answer.
150     * @param \Illuminate\Support\Carbon     $start   The wanted start period.
151     * @param \Illuminate\Support\Carbon     $end     The wanted end period.
152     * @return \Illuminate\Support\Collection A collection with date as Y_m_d index with array of answers
153     * and their total.
154     */
155    private function answersByDays(Collection $answers, Carbon $start, Carbon $end): Collection
156    {
157        // * Totalize by date all answers.
158        $answersByDays = CustomerAnswer::whereDate('created_at', '>=', $start)
159            ->whereDate('created_at', '<=', $end)
160            ->whereIn('answer_id', $answers->pluck('id'))
161            ->get()->map(function ($custAnswer) {
162                return [
163                    'answer_id' => $custAnswer->answer_id,
164                    'created_at' => $custAnswer->created_at->format('Y-m-d'),
165                ];
166            })->groupBy(['created_at', 'answer_id'])->map(function ($day) {
167                return $day->map(function ($custAnswers) {
168                    return $custAnswers->count();
169                });
170            });
171
172        do {
173            $currentDate = $start->format('Y-m-d');
174            /** @var \Illuminate\Support\Collection $answersByDays */
175            if (!$answersByDays->has($currentDate)) {
176                $answersByDays->put(
177                    $currentDate,
178                    $answers->mapWithKeys(function ($answer) {
179                        return [$answer->answer => 0];
180                    })
181                );
182            } else {
183                $curentAnswers = $answersByDays->pull($currentDate);
184                $answersByDays->put(
185                    $currentDate,
186                    $answers->mapWithKeys(function ($answer) use ($curentAnswers) {
187                        return [$answer->answer =>
188                        $curentAnswers->has($answer->id) ?
189                        $curentAnswers->get($answer->id) : 0];
190                    })
191                );
192            }
193
194            $start = $start->addDay();
195        } while ($start->lessThanOrEqualTo($end));
196
197        return $answersByDays;
198    }
199}