Completed
Push — master ( d964e4...900267 )
by Jeroen
23:03 queued 15:42
created

ExportService::streamOutput()   B

Complexity

Conditions 8
Paths 1

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 50.875

Importance

Changes 0
Metric Value
dl 0
loc 53
ccs 4
cts 32
cp 0.125
rs 7.781
c 0
b 0
f 0
cc 8
nc 1
nop 2
crap 50.875

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Kunstmaan\AdminListBundle\Service;
4
5
use Box\Spout\Common\Type;
6
use Box\Spout\Writer\WriterFactory;
7
use Kunstmaan\AdminListBundle\AdminList\ExportableInterface;
8
use Kunstmaan\AdminListBundle\AdminList\Field;
9
use Kunstmaan\AdminListBundle\Exception\ExportException;
10
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
11
use Symfony\Component\HttpFoundation\StreamedResponse;
12
use Symfony\Component\Translation\Translator;
13
use Symfony\Component\Translation\TranslatorInterface as LegaceTranslatorInterface;
14
use Symfony\Contracts\Translation\TranslatorInterface;
15
use Twig\Environment;
16
17
/**
18
 * class ExportService
19
 */
20
class ExportService
21
{
22
    const SUPPORTED_EXTENSIONS = [
23
        'Csv' => Type::CSV,
24
        'Ods' => Type::ODS,
25
        'Excel' => Type::XLSX,
26
    ];
27
28
    /**
29
     * @return array
30
     */
31 1
    public static function getSupportedExtensions()
32
    {
33 1
        return self::SUPPORTED_EXTENSIONS;
34
    }
35
36
    /**
37
     * @var EngineInterface|Environment
38
     */
39
    private $renderer;
40
41
    /**
42
     * @var Translator
43
     */
44
    private $translator;
45
46 7
    public function __construct(Environment $twig = null, $translator = null)
47
    {
48 7
        if (null === $twig) {
49 2
            @trigger_error(sprintf('Not passing the Twig service as the first argument of "%s" is deprecated since KunstmaanAdminListBundle 5.4 and will be required in KunstmaanAdminListBundle 6.0. Injected the required services in the constructor instead.', __METHOD__), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
50
        }
51
52 7
        if (null === $translator) {
53 2
            @trigger_error(sprintf('Not passing the "translator" service as the second argument of "%s" is deprecated since KunstmaanAdminListBundle 5.4 and will be required in KunstmaanAdminListBundle 6.0. Injected the required services in the constructor instead.', __METHOD__), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
54
        }
55
56 7
        if (null !== $translator && (!$translator instanceof LegaceTranslatorInterface && !$translator instanceof TranslatorInterface)) {
57 1
            throw new \InvalidArgumentException(sprintf('Argument 2 passed to "%s" must be of the type "%s" or "%s", "%s" given', __METHOD__, LegaceTranslatorInterface::class, TranslatorInterface::class, get_class($translator)));
58
        }
59
60 7
        $this->renderer = $twig;
61 7
        $this->translator = $translator;
62 7
    }
63
64
    /**
65
     * @param ExportableInterface $adminList
66
     * @param string              $format
67
     *
68
     * @return StreamedResponse
69
     *
70
     * @throws ExportException
71
     */
72 3
    public function getDownloadableResponse(ExportableInterface $adminList, $format)
73
    {
74 3
        return $this->streamOutput($adminList, $format);
75
    }
76
77
    /**
78
     * @param ExportableInterface $adminList
79
     * @param string              $format
80
     *
81
     * @return StreamedResponse
82
     *
83
     * @throws ExportException
84
     */
85 3
    protected function streamOutput(ExportableInterface $adminList, $format)
86
    {
87 3
        $response = new StreamedResponse();
88
        $response->setCallback(function () use ($adminList, $format) {
89
            $writer = WriterFactory::create($format);
90
            $writer->openToBrowser('export.'.$format);
91
92
            $row = [];
93
            /** @var Field $column */
94
            foreach ($adminList->getExportColumns() as $column) {
95
                $row[] = $this->translator->trans($column->getHeader());
96
            }
97
            $writer->addRow($row);
98
99
            $iterator = $adminList->getIterator();
100
            $rows = [];
101
            foreach ($iterator as $item) {
102
                if (\array_key_exists(0, $item)) {
103
                    $itemObject = $item[0];
104
                } else {
105
                    $itemObject = $item;
106
                }
107
108
                $row = [];
109
                /** @var Field $column */
110
                foreach ($adminList->getExportColumns() as $column) {
111
                    $columnName = $column->getName();
112
                    $itemHelper = $itemObject;
113
                    if ($column->hasAlias()) {
114
                        $itemHelper = $column->getAliasObj($itemObject);
115
                        $columnName = $column->getColumnName($columnName);
116
                    }
117
                    $data = $adminList->getStringValue($itemHelper, $columnName);
118
                    if (null !== $column->getTemplate()) {
119
                        // NEXT_MAJOR: Remove `templateExists` private method and call Twig exists check directly.
120
                        if (!$this->templateExists($column->getTemplate())) {
121
                            throw new ExportException('No export template defined for ' . \get_class($data), $data);
122
                        }
123
124
                        $data = $this->renderer->render($column->getTemplate(), ['object' => $data]);
125
                    }
126
127
                    $row[] = $data;
128
                }
129
                $rows[] = $row;
130
            }
131
132
            $writer->addRows($rows);
133
            $writer->close();
134 3
        });
135
136 3
        return $response;
137
    }
138
139
    /**
140
     * @deprecated Setter injection is deprecation since KunstmaanAdminListBundle 5.4 and will be removed in KunstmaanAdminListBundle 6.0. Use constructor injection instead.
141
     *
142
     * @param EngineInterface $renderer
143
     */
144 1
    public function setRenderer($renderer)
145
    {
146 1
        if (!$this->renderer instanceof Environment) {
147 1
            if ($renderer instanceof EngineInterface) {
148 1
                @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
149 1
                    sprintf('Injecting the template renderer with "%s" is deprecated since KunstmaanAdminListBundle 5.4 and will be removed in KunstmaanAdminListBundle 6.0. Inject Twig with constructor injection instead.', __METHOD__),
150 1
                    E_USER_DEPRECATED
151
                );
152
            }
153
154
            // Renderer was not set in the constructor, so set it here to the deprecated templating renderer. Constructor
155
            // value has precedence over the setter because the implementation is switched to twig.
156 1
            $this->renderer = $renderer;
157
        }
158 1
    }
159
160
    /**
161
     * @deprecated Setter injection is deprecation since KunstmaanAdminListBundle 5.4 and will be removed in KunstmaanAdminListBundle 6.0. Use constructor injection instead.
162
     *
163
     * @param Translator $translator
164
     */
165 1
    public function setTranslator($translator)
166
    {
167 1
        if (!$this->translator instanceof LegaceTranslatorInterface && !$this->translator instanceof TranslatorInterface) {
168 1
            if ($translator instanceof LegaceTranslatorInterface || $translator instanceof TranslatorInterface) {
169
                //Trigger deprecation because setter is deprecated, translator should be injected in the constructor
170 1
                @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
171 1
                    sprintf('Injecting the translator with "%s" is deprecated since KunstmaanAdminListBundle 5.4 and will be removed in KunstmaanAdminListBundle 6.0. Inject the Translator with constructor injection instead.', __METHOD__),
172 1
                    E_USER_DEPRECATED
173
                );
174
            }
175
176 1
            $this->translator = $translator;
177
        }
178 1
    }
179
180
    private function templateExists(string $template)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
181
    {
182
        if ($this->renderer instanceof EngineInterface) {
183
            return $this->renderer->exists($template);
184
        }
185
186
        return $this->renderer->getLoader()->exists($template);
187
    }
188
}
189