Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
AppArchiver
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 6
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDirectory
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFiles
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 backup
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 rotate
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 sendLatestArchive
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\App\Models\Domain;
6
7use Exception;
8use PeServer\App\Models\AppConfiguration;
9use PeServer\App\Models\AppDatabaseConnection;
10use PeServer\App\Models\AppMailer;
11use PeServer\Core\Archiver;
12use PeServer\Core\Binary;
13use PeServer\Core\Collection\Arr;
14use PeServer\Core\Environment;
15use PeServer\Core\IO\Directory;
16use PeServer\Core\IO\File;
17use PeServer\Core\IO\Path;
18use PeServer\Core\Log\ILogger;
19use PeServer\Core\Log\ILoggerFactory;
20use PeServer\Core\Mail\Attachment;
21use PeServer\Core\Mail\EmailAddress;
22use PeServer\Core\Mail\EmailMessage;
23use PeServer\Core\Mvc\ILogicFactory;
24use PeServer\Core\Text;
25use PeServer\Core\Throws\InvalidOperationException;
26use PeServer\Core\Utc;
27use ZipArchive;
28
29class AppArchiver
30{
31    #region define
32
33    /** 保持ファイル数。 */
34    private const MAX_COUNT = 180;
35
36    #endregion
37
38    #region property
39
40    private ILogger $logger;
41
42    #endregion
43
44    public function __construct(
45        private Environment $environment,
46        private AppConfiguration $config,
47        private AppMailer $mailer,
48        ILoggerFactory $loggerFactory,
49    ) {
50        $this->logger = $loggerFactory->createLogger($this);
51    }
52
53    public function getDirectory(): string
54    {
55        return $this->config->setting->cache->backup;
56    }
57
58    /**
59     * アーカイブファイル一覧の取得。
60     *
61     * @return string[]
62     */
63    public function getFiles(): array
64    {
65        return Directory::find($this->getDirectory(), '*.zip');
66    }
67
68    public function backup(): int
69    {
70        $revision = $this->environment->getRevision();
71        $fileName = Utc::create()->format('Y-m-d\_His') . "_{$revision}.zip";
72        $filePath = Path::combine($this->getDirectory(), $fileName);
73        Directory::createParentDirectoryIfNotExists($filePath);
74
75        $zipArchive = new ZipArchive();
76        $zipArchive->open($filePath, ZipArchive::CREATE | ZipArchive::EXCL);
77
78        //DB保存
79        $databasePath = AppDatabaseConnection::getSqliteFilePath($this->config->setting->persistence->default->connection);
80        $zipArchive->addFile($databasePath, Path::getFileName($databasePath));
81        // 設定ファイル保存
82        $settingName = Path::setEnvironmentName('setting.json', $this->environment->get());
83        $settingPath = Path::combine($this->config->settingDirectoryPath, $settingName);
84        $zipArchive->addFile($settingPath, $settingName);
85
86        $zipArchive->close();
87
88        return File::getFileSize($filePath);
89    }
90
91    public function rotate(): void
92    {
93        $backupFiles = $this->getFiles();
94        $logCount = Arr::getCount($backupFiles);
95        if ($logCount <= self::MAX_COUNT) {
96            return;
97        }
98
99        $length = $logCount - self::MAX_COUNT;
100        for ($i = 0; $i < $length; $i++) {
101            File::removeFile($backupFiles[$i]);
102        }
103    }
104
105    public function sendLatestArchive(string $subject, bool $ignoreError): void
106    {
107        $backupFiles = $this->getFiles();
108        if (Arr::isNullOrEmpty($backupFiles)) {
109            if ($ignoreError) {
110                return;
111            }
112            throw new InvalidOperationException();
113        }
114
115        $backupFilePath = $backupFiles[count($backupFiles) - 1];
116        $backupFileName = Path::getFileName($backupFilePath);
117        assert(!Text::isNullOrWhiteSpace($backupFileName));
118
119        $this->mailer->subject = "[Backup] {$subject} {$backupFileName}";
120        $this->mailer->setMessage(new EmailMessage(
121            "バックアップ実施"
122        ));
123        $this->mailer->attachments[] = new Attachment(
124            $backupFileName,
125            File::readContent($backupFilePath)
126        );
127
128        foreach ($this->config->setting->config->address->notify->maintenance as $email) {
129            $this->mailer->toAddresses = [
130                new EmailAddress($email),
131            ];
132
133            try {
134                $this->mailer->send();
135            } catch (Exception $ex) {
136                $this->logger->error($ex);
137                if (!$ignoreError) {
138                    throw $ex;
139                }
140            }
141        }
142    }
143}