Passed
Push — master ( f747df...a125fa )
by Anton
07:27 queued 05:22
created

FileSnapshooter::saveSnapshot()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 9
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Snapshots;
13
14
use Psr\Log\LoggerInterface;
15
use Spiral\Exceptions\HandlerInterface;
16
use Spiral\Files\Exception\FilesException;
17
use Spiral\Files\FilesInterface;
18
use Symfony\Component\Finder\Finder;
19
use Symfony\Component\Finder\SplFileInfo;
20
21
final class FileSnapshooter implements SnapshotterInterface
22
{
23
    /** @var string */
24
    private $directory;
25
26
    /** @var int */
27
    private $maxFiles;
28
29
    /** @var int */
30
    private $verbosity;
31
32
    /** @var HandlerInterface */
33
    private $handler;
34
35
    /** @var FilesInterface */
36
    private $files;
37
38
    /** @var LoggerInterface|null */
39
    private $logger;
40
41
    /**
42
     * @param string               $directory
43
     * @param int                  $maxFiles
44
     * @param int                  $verbosity
45
     * @param HandlerInterface     $handler
46
     * @param FilesInterface       $files
47
     * @param LoggerInterface|null $logger
48
     */
49
    public function __construct(
50
        string $directory,
51
        int $maxFiles,
52
        int $verbosity,
53
        HandlerInterface $handler,
54
        FilesInterface $files,
55
        LoggerInterface $logger = null
56
    ) {
57
        $this->directory = $directory;
58
        $this->maxFiles = $maxFiles;
59
        $this->verbosity = $verbosity;
60
        $this->handler = $handler;
61
        $this->files = $files;
62
        $this->logger = $logger;
63
    }
64
65
    /**
66
     * @inheritdoc
67
     */
68
    public function register(\Throwable $e): SnapshotInterface
69
    {
70
        $snapshot = new Snapshot($this->getID($e), $e);
71
72
        if ($this->logger !== null) {
73
            $this->logger->error($snapshot->getMessage());
74
        }
75
76
        $this->saveSnapshot($snapshot);
77
        $this->rotateSnapshots();
78
79
        return $snapshot;
80
    }
81
82
    /**
83
     * @param SnapshotInterface $snapshot
84
     * @throws \Exception
85
     */
86
    protected function saveSnapshot(SnapshotInterface $snapshot): void
87
    {
88
        $filename = $this->getFilename($snapshot, new \DateTime());
89
90
        $this->files->write(
91
            $filename,
92
            $this->handler->renderException($snapshot->getException(), $this->verbosity),
93
            FilesInterface::RUNTIME,
94
            true
95
        );
96
    }
97
98
    /**
99
     * Remove older snapshots.
100
     */
101
    protected function rotateSnapshots(): void
102
    {
103
        $finder = new Finder();
104
        $finder->in($this->directory)->sort(function (SplFileInfo $a, SplFileInfo $b) {
105
            return $b->getMTime() - $a->getMTime();
106
        });
107
108
        $count = 0;
109
        foreach ($finder as $file) {
110
            $count++;
111
            if ($count > $this->maxFiles) {
112
                try {
113
                    $this->files->delete($file->getRealPath());
114
                } catch (FilesException $e) {
115
                    // ignore
116
                }
117
            }
118
        }
119
    }
120
121
    /**
122
     * @param SnapshotInterface  $snapshot
123
     * @param \DateTimeInterface $time
124
     * @return string
125
     *
126
     * @throws \Exception
127
     */
128
    protected function getFilename(SnapshotInterface $snapshot, \DateTimeInterface $time): string
129
    {
130
        return sprintf(
131
            '%s/%s-%s.txt',
132
            $this->directory,
133
            $time->format('d.m.Y-Hi.s'),
134
            (new \ReflectionClass($snapshot->getException()))->getShortName()
135
        );
136
    }
137
138
    /**
139
     * @param \Throwable $e
140
     * @return string
141
     */
142
    protected function getID(\Throwable $e): string
143
    {
144
        return md5(join('|', [$e->getMessage(), $e->getFile(), $e->getLine()]));
145
    }
146
}
147