Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApplicationApiCrashReportLogic
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 3
72
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 validateImpl
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 executeImpl
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\App\Models\Domain\Api\ApplicationApi;
6
7use Exception;
8use PeServer\App\Models\AppConfiguration;
9use PeServer\App\Models\AppCryptography;
10use PeServer\App\Models\AppMailer;
11use PeServer\App\Models\AppTemplate;
12use PeServer\App\Models\AuditLog;
13use PeServer\App\Models\Dao\Entities\CrashReportsEntityDao;
14use PeServer\App\Models\Dao\Entities\SequenceEntityDao;
15use PeServer\App\Models\Domain\Api\ApiLogicBase;
16use PeServer\App\Models\ResponseJson;
17use PeServer\Core\Archiver;
18use PeServer\Core\Database\IDatabaseContext;
19use PeServer\Core\Mail\Attachment;
20use PeServer\Core\Mail\EmailAddress;
21use PeServer\Core\Mail\EmailMessage;
22use PeServer\Core\Mime;
23use PeServer\Core\Mvc\LogicCallMode;
24use PeServer\Core\Mvc\LogicParameter;
25use PeServer\Core\Serialization\JsonSerializer;
26use PeServer\Core\Text;
27use PeServer\Core\Throws\NotImplementedException;
28
29class ApplicationApiCrashReportLogic extends ApiLogicBase
30{
31    #region variable
32
33    /**
34     * 要求JSON
35     *
36     * @var array<string,mixed>
37     */
38    private array $requestJson;
39
40    #endregion
41
42    public function __construct(LogicParameter $parameter, private AppConfiguration $config, private AppCryptography $appCryptography, private AppMailer $mailer, private AppTemplate $appTemplate)
43    {
44        parent::__construct($parameter);
45
46        $this->requestJson = $this->getRequestJson();
47    }
48
49    #region ApiLogicBase
50
51    protected function validateImpl(LogicCallMode $callMode): void
52    {
53        $this->validateJsonProperty($this->requestJson, 'version', self::VALIDATE_JSON_PROPERTY_NON_EMPTY_TEXT);
54        $this->validateJsonProperty($this->requestJson, 'revision', self::VALIDATE_JSON_PROPERTY_NON_EMPTY_TEXT);
55        $this->validateJsonProperty($this->requestJson, 'build', self::VALIDATE_JSON_PROPERTY_NON_EMPTY_TEXT);
56        $this->validateJsonProperty($this->requestJson, 'user_id', self::VALIDATE_JSON_PROPERTY_NON_EMPTY_TEXT);
57        $this->validateJsonProperty($this->requestJson, 'exception', self::VALIDATE_JSON_PROPERTY_NON_EMPTY_TEXT);
58        $this->validateJsonProperty($this->requestJson, 'mail_address', self::VALIDATE_JSON_PROPERTY_TEXT);
59        $this->validateJsonProperty($this->requestJson, 'comment', self::VALIDATE_JSON_PROPERTY_TEXT);
60
61        // 完全に実装ミス
62        if ($this->hasError()) {
63            throw new Exception();
64        }
65    }
66
67    protected function executeImpl(LogicCallMode $callMode): void
68    {
69        $mailAddress = Text::isNullOrWhiteSpace($this->requestJson['mail_address'])
70            ? Text::EMPTY
71            : $this->appCryptography->encrypt($this->requestJson['mail_address']);
72        $requestJson = $this->requestJson;
73        unset($requestJson['mail_address']);
74
75        $binaryReport = (new JsonSerializer())->save($requestJson);
76        $compressReport = Archiver::compressGzip($binaryReport);
77
78        $sequence = 0;
79
80        $database = $this->openDatabase();
81        $result = $database->transaction(function (IDatabaseContext $context) use ($mailAddress, $requestJson, $compressReport, &$sequence) {
82            $crashReportsEntityDao = new CrashReportsEntityDao($context);
83            $crashReportsEntityDao->insertCrashReports(
84                $this->stores->special->getServer('REMOTE_ADDR'),
85                $requestJson['version'],
86                $requestJson['revision'],
87                $requestJson['build'],
88                $requestJson['user_id'],
89                $requestJson['exception'],
90                $mailAddress,
91                $requestJson['comment'] ?? Text::EMPTY,
92                $compressReport
93            );
94
95            $sequenceEntityDao = new SequenceEntityDao($context);
96
97            $sequence = $sequenceEntityDao->getLastSequence();
98
99            $this->setContent(Mime::JSON, [
100                'success' => true,
101                'message' => '',
102            ]);
103
104            return true;
105        });
106
107        if (!$result) {
108            // 完全に実装ミス
109            throw new Exception();
110        }
111
112        // メール送信
113        $crashReportEmails = $this->config->setting->config->address->notify->crashReport;
114        $exception = Text::splitLines($requestJson['exception'])[0];
115
116        $this->mailer->customSubjectHeader = '[Pe-CrashReport]';
117        $this->mailer->subject = "$sequence$exception";
118        $message = $this->appTemplate->createMailTemplate('crash_report_email', $this->mailer->subject, $requestJson);
119        $this->mailer->setMessage(new EmailMessage($message));
120        $this->mailer->attachments[] = new Attachment("report-$sequence.json", $this->getRequestContent(), Mime::JSON);
121        foreach ($crashReportEmails as $crashReportEmail) {
122            $this->mailer->toAddresses = [
123                new EmailAddress($crashReportEmail),
124            ];
125
126            try {
127                $this->mailer->send();
128            } catch (Exception $ex) {
129                // メール送信は開発側の都合なのでエラーならログに記録するのみ
130                $this->logger->error($ex);
131            }
132        }
133    }
134
135    #endregion
136}