Passed
Push — master ( 6957cf...3bb145 )
by Joachim
04:59
created

ReportWriter::generateTempPath()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Setono\SyliusStockMovementPlugin\Writer;
6
7
use InvalidArgumentException;
8
use League\Flysystem\FilesystemInterface;
9
use Safe\Exceptions\FilesystemException;
10
use Safe\Exceptions\OutcontrolException;
11
use Safe\Exceptions\StringsException;
12
use function Safe\fopen;
13
use function Safe\fwrite;
14
use function Safe\ob_end_clean;
15
use function Safe\sprintf;
16
use Setono\SyliusStockMovementPlugin\Model\ReportInterface;
17
use Setono\SyliusStockMovementPlugin\Resolver\ReportPathResolverInterface;
18
use Throwable;
19
use Twig\Environment;
20
use Twig\Error\LoaderError;
21
use Twig\Error\RuntimeError;
22
use Twig\Error\SyntaxError;
23
24
class ReportWriter implements ReportWriterInterface
25
{
26
    /** @var Environment */
27
    private $twig;
28
29
    /** @var FilesystemInterface */
30
    private $filesystem;
31
32
    /** @var ReportPathResolverInterface */
33
    private $reportPathResolver;
34
35
    public function __construct(Environment $twig, FilesystemInterface $filesystem, ReportPathResolverInterface $reportPathResolver)
36
    {
37
        $this->filesystem = $filesystem;
38
        $this->twig = $twig;
39
        $this->reportPathResolver = $reportPathResolver;
40
    }
41
42
    /**
43
     * @throws FilesystemException
44
     * @throws OutcontrolException
45
     * @throws StringsException
46
     * @throws Throwable
47
     * @throws LoaderError
48
     * @throws RuntimeError
49
     * @throws SyntaxError
50
     */
51
    public function write(ReportInterface $report): string
52
    {
53
        $key = $this->reportPathResolver->resolve($report);
54
        // todo should we provide some kind of 'overwrite' parameter?
55
        if ($this->filesystem->has($key)) {
56
            return $key;
57
        }
58
59
        $reportConfiguration = $report->getReportConfiguration();
60
        if (null === $reportConfiguration) {
61
            throw new \RuntimeException(sprintf('No report configuration associated with report %s', $report->getId()));
62
        }
63
64
        $template = $this->twig->load($reportConfiguration->getTemplate());
65
66
        $definedBlocks = $template->getBlockNames();
67
        foreach (['extension', 'body'] as $block) {
68
            if (!in_array($block, $definedBlocks, true)) {
69
                throw new InvalidArgumentException(sprintf(
70
                    'The block "%s" is not present in the defined blocks ["%s"] of your template %s',
71
                    $block,
72
                    implode('", "', $definedBlocks),
73
                    $reportConfiguration->getTemplate()
74
                )); // todo better exception
75
            }
76
        }
77
78
        $path = $this->generateTempPath();
79
80
        $fp = fopen($path, 'w+b'); // needs to be w+ since we use the same stream later to read from
81
82
        ob_start(static function ($buffer) use ($fp) {
83
            fwrite($fp, $buffer);
84
        }, 1024);
85
86
        $template->displayBlock('body', [
87
            'stockMovements' => $report->getStockMovements(),
88
        ]);
89
90
        ob_end_clean();
91
92
        $this->filesystem->writeStream($key, $fp); // todo throw exception if it returns false
93
94
        return $key;
95
    }
96
97
    private function generateTempPath(): string
98
    {
99
        do {
100
            $path = sys_get_temp_dir() . '/' . uniqid('stock-movement-report-', true);
101
        } while (file_exists($path));
102
103
        return $path;
104
    }
105
}
106