• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ericfortmeyer / activity-log / 20488915339

24 Dec 2025 03:11PM UTC coverage: 49.13% (-2.7%) from 51.874%
20488915339

push

github

web-flow
fix: add support for emailing reports (#62)

Fixes #9

Signed-off-by: Eric Fortmeyer <e.fortmeyer01@gmail.com>

72 of 224 new or added lines in 12 files covered. (32.14%)

5 existing lines in 3 files now uncovered.

339 of 690 relevant lines covered (49.13%)

1.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Http/RequestProcessors/EmailReportForMonth.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace EricFortmeyer\ActivityLog\Http\RequestProcessors;
6

7
use EricFortmeyer\ActivityLog\{
8
    CreditHours,
9
    TimeEntry,
10
    EmailConfig,
11
    MonthFilters,
12
    RemarksForMonth,
13
    EmailReport
14
};
15
use EricFortmeyer\ActivityLog\UserInterface\Contexts\TimeEntriesContext;
16
use EricFortmeyer\ActivityLog\Services\{
17
    TimeEntryService,
18
    RemarksForMonthService,
19
    CreditHoursService,
20
    TemplateBinder,
21
};
22
use EricFortmeyer\ActivityLog\UserInterface\Contexts\EmailReportContext;
23
use EricFortmeyer\ActivityLog\UserInterface\Contexts\ServerErrorContext;
24
use EricFortmeyer\ActivityLog\Utils\Hasher;
25
use Phpolar\Model\Model;
26
use Phpolar\Phpolar\Auth\Authorize;
27
use Phpolar\PurePhp\HtmlSafeContext;
28
use Phpolar\Storage\NotFound;
29

30
final class EmailReportForMonth extends AbstractTenantBasedRequestProcessor
31
{
32
    public function __construct(
33
        private readonly EmailConfig $mailConfig,
34
        private readonly TimeEntryService $timeEntryService,
35
        private readonly RemarksForMonthService $remarksService,
36
        private readonly CreditHoursService $creditHoursService,
37
        private readonly TemplateBinder $templateEngine,
38
        readonly Hasher $hasher,
39
    ) {
40
        parent::__construct($hasher);
×
41
    }
42

43
    #[Authorize]
44
    public function process(
45
        #[Model] EmailReport $emailReport = new EmailReport(),
46
        #[Model] MonthFilters $monthFilters = new MonthFilters(),
47
    ): string {
NEW
48
        $month = $emailReport->month;
×
NEW
49
        $year = $emailReport->year;
×
50
        $timeEntries = $this->timeEntryService->getAllByMonth(
×
51
            month: $month,
×
52
            year: $year,
×
53
            tenantId: $this->getTenantId(),
×
54
        );
×
55
        $remarks = $this->remarksService->get(RemarksForMonth::getIdFromMonth(
×
56
            month: $month,
×
57
            year: $year,
×
58
            tenantId: $this->getTenantId(),
×
59
        ));
×
60
        $creditHours = $this->creditHoursService->get(CreditHours::getIdFromMonth(
×
61
            month: $month,
×
62
            year: $year,
×
63
            tenantId: $this->getTenantId(),
×
64
        ));
×
NEW
65
        $currentEntry = new TimeEntry();
×
NEW
66
        TimeEntry::setUninitializedValues(
×
NEW
67
            $currentEntry,
×
NEW
68
            $month,
×
NEW
69
            $year,
×
70
        );
×
71

NEW
72
        if ($emailReport->isValid() === true) {
×
NEW
73
            $success = mail(
×
NEW
74
                to: $emailReport->mailTo,
×
NEW
75
                subject: $emailReport->getSubject($this->user),
×
NEW
76
                message: $this->templateEngine->apply(
×
NEW
77
                    "email-report",
×
NEW
78
                    new EmailReportContext(
×
NEW
79
                        emailReport: $emailReport,
×
NEW
80
                        timeEntries: $timeEntries,
×
NEW
81
                        currentEntry: $currentEntry,
×
NEW
82
                        filters: $monthFilters,
×
NEW
83
                        remarks: $remarks,
×
NEW
84
                        creditHours: $creditHours,
×
NEW
85
                    ),
×
NEW
86
                ),
×
NEW
87
                additional_headers: $this->mailConfig->headers,
×
NEW
88
            );
×
89

NEW
90
            if ($success === false) {
×
NEW
91
                $error = error_get_last();
×
NEW
92
                if ($error !== null) {
×
NEW
93
                    ["message" => $message] = $error;
×
NEW
94
                    return $this->templateEngine->apply(
×
NEW
95
                        "500",
×
NEW
96
                        new HtmlSafeContext(
×
NEW
97
                            new ServerErrorContext(
×
NEW
98
                                message: $message,
×
NEW
99
                            ),
×
NEW
100
                        ),
×
NEW
101
                    );
×
102
                }
103
            }
104

NEW
105
            $emailReport->isPosted();
×
106
        }
107

108

NEW
109
        return $this->templateEngine->apply(
×
NEW
110
            "index",
×
NEW
111
            $this->getContext(
×
NEW
112
                currentEntry: $currentEntry,
×
NEW
113
                timeEntries: $timeEntries,
×
NEW
114
                monthFilters: $monthFilters,
×
NEW
115
                remarks: $remarks,
×
NEW
116
                creditHours: $creditHours,
×
NEW
117
            )
×
NEW
118
        );
×
119
    }
120

121
    /**
122
     * @param TimeEntry[] $timeEntries
123
     */
124
    private function getContext(
125
        TimeEntry $currentEntry,
126
        array $timeEntries,
127
        MonthFilters $monthFilters,
128
        RemarksForMonth| NotFound $remarks,
129
        CreditHours|NotFound $creditHours,
130
    ): TimeEntriesContext {
131
        return match (true) {
×
132
            $remarks instanceof NotFound && $creditHours instanceof NotFound =>
×
133
            new TimeEntriesContext(
×
NEW
134
                currentEntry: $currentEntry,
×
135
                timeEntries: $timeEntries,
×
136
                tenantId: $this->getTenantId(),
×
137
                filters: $monthFilters,
×
138
                user: $this->user
×
139
            ),
×
140
            $creditHours instanceof CreditHours && $remarks instanceof NotFound =>
×
141
            new TimeEntriesContext(
×
NEW
142
                currentEntry: $currentEntry,
×
143
                timeEntries: $timeEntries,
×
144
                tenantId: $this->getTenantId(),
×
145
                filters: $monthFilters,
×
146
                creditHours: $creditHours,
×
147
                user: $this->user
×
148
            ),
×
149
            $creditHours instanceof CreditHours && $remarks instanceof RemarksForMonth =>
×
150
            new TimeEntriesContext(
×
NEW
151
                currentEntry: $currentEntry,
×
152
                timeEntries: $timeEntries,
×
153
                tenantId: $this->getTenantId(),
×
154
                filters: $monthFilters,
×
155
                remarks: $remarks,
×
156
                creditHours: $creditHours,
×
157
                user: $this->user,
×
158
            ),
×
159
            $remarks instanceof RemarksForMonth && $creditHours instanceof NotFound =>
×
160
            new TimeEntriesContext(
×
NEW
161
                currentEntry: $currentEntry,
×
162
                timeEntries: $timeEntries,
×
163
                tenantId: $this->getTenantId(),
×
164
                filters: $monthFilters,
×
165
                remarks: $remarks,
×
166
                user: $this->user
×
167
            ),
×
168
            default =>
×
169
            new TimeEntriesContext(
×
NEW
170
                currentEntry: $currentEntry,
×
171
                user: $this->user,
×
172
                tenantId: $this->getTenantId(),
×
173
            )
×
174
        };
×
175
    }
176
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc