Completed
Pull Request — develop (#542)
by Mathias
09:01
created

Module::renderFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 19
c 0
b 0
f 0
ccs 0
cts 6
cp 0
rs 10
cc 1
nc 1
nop 1
crap 2
1
<?php
2
/**
3
 * YAWIK
4
 * Auth Module Bootstrap
5
 *
6
 * @copyright (c) 2013 - 2016 Cross Solution (http://cross-solution.de)
7
 * @license   MIT
8
 */
9
10
namespace Pdf;
11
12
use Zend\ServiceManager\ServiceManager;
13
use SplFileInfo;
14
use Zend\View\Resolver\ResolverInterface;
15
use Zend\View\Renderer\RendererInterface as Renderer;
16
use Zend\Mvc\MvcEvent;
17
use Zend\View\ViewEvent;
18
use Zend\EventManager\EventManagerInterface;
19
use Core\Html2Pdf\PdfInterface;
20
use Core\View\Helper\InsertFile\FileEvent;
21
use Core\Entity\FileEntity;
22
use Core\ModuleManager\ModuleConfigLoader;
23
24
/**
25
 * Make HTML to PDF
26
 *
27
 */
28
class Module implements PdfInterface, ResolverInterface
29
{
30
    const RENDER_FULL = 0;
31
    const RENDER_WITHOUT_PDF = 1;
32
    const RENDER_WITHOUT_ATTACHMENTS = 2;
33
    
34
    protected $serviceManager;
35
    
36
    protected $viewResolverAttached = false;
37
    
38
    protected $appendPDF = array();
39
    protected $appendImage = array();
40
    
41
    
42
    /**
43
    * Loads module specific configuration.
44
    *
45
    * @return array
46
    */
47 5
    public function getConfig()
48
    {
49 5
        return ModuleConfigLoader::load(__DIR__ . '/../config');
50
    }
51
    
52
    public static function factory(ServiceManager $serviceManager)
53
    {
54
        $module = new static();
55
        $module->serviceManager = $serviceManager;
56
        return $module;
57
    }
58
    
59 4
    public function onBootstrap(MvcEvent $e)
60
    {
61 4
        $eventManager = $e->getApplication()->getEventManager();
62 4
        $eventManager->getSharedManager()->attach(
63 4
            'Applications',
64 4
            'application.detail.actionbuttons',
65
            function ($event) {
0 ignored issues
show
Unused Code introduced by
The parameter $event is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

65
            function (/** @scrutinizer ignore-unused */ $event) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
66
                return 'pdf/application/details/button';
67 4
            }
68
        );
69 4
    }
70
    
71
    /**
72
     * hook into the rendering for transformation of HTML to PDF
73
     * @param \Zend\EventManager\EventManagerInterface $events
74
     */
75
    public function attach(EventManagerInterface $events)
76
    {
77
        $events->attach(ViewEvent::EVENT_RENDERER_POST, array($this, 'cleanLayout'), 1);
78
        $events->attach(ViewEvent::EVENT_RESPONSE, array($this, 'attachPDFtransformer'), 10);
79
    }
80
    
81
    /**
82
     * hook into the MVC
83
     * in here you could still decide, if you want to hook into the Rendering
84
     * @param \Zend\EventManager\EventManagerInterface $events
85
     */
86
    public function attachMvc(EventManagerInterface $events)
87
    {
88
        $events->attach(MvcEvent::EVENT_RENDER, array($this, 'initializeViewHelper'), 100);
89
    }
90
    
91
    /**
92
     * hook into the Rendering of files
93
     * the manager to hook in is the viewhelper 'insertfiles'
94
     *
95
     * @param \Zend\Mvc\MvcEvent $e
96
     */
97
    public function initializeViewHelper(MvcEvent $e)
0 ignored issues
show
Unused Code introduced by
The parameter $e is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

97
    public function initializeViewHelper(/** @scrutinizer ignore-unused */ MvcEvent $e)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
98
    {
99
        $viewhelperManager = $this->serviceManager->get('ViewHelperManager');
100
        if ($viewhelperManager->has('InsertFile')) {
101
            $insertFile = $viewhelperManager->get('InsertFile');
102
            $insertFile->attach(FileEvent::GETFILE, array($this, 'getFile'));
103
            $insertFile->attach(FileEvent::RENDERFILE, array($this, 'renderFile'));
104
            $insertFile->attach(FileEvent::INSERTFILE, array($this, 'collectFiles'));
105
        }
106
    }
107
    
108
    /**
109
     * proxy, in case that you just got a name and have to find the associated file-entity
110
     * maybe this is redundant and can be deprecated
111
     *
112
     * @param \Core\View\Helper\InsertFile\FileEvent $e
113
     * @return null
114
     */
115
    public function getFile(FileEvent $e)
116
    {
117
        $lastFileName = $e->getLastFileName();
118
        if (is_string($lastFileName)) {
119
            $repository = $this->serviceManager->get('repositories')->get('Applications/Attachment');
120
            $file       = $repository->find($lastFileName);
121
            if (isset($file)) {
122
                $e->setFileObject($lastFileName, $file);
123
                $e->stopPropagation();
124
                return $file;
125
            }
126
            return null;
127
        }
128
        // if it is not a string i do presume it is already a file-Object
129
        return $lastFileName;
130
    }
131
    
132
    /**
133
     * here the inserted File is rendered,
134
     * there is a lot which still can be done like outsorcing the HTML to a template,
135
     * or distinguish between different File Types,
136
     * at the moment we assume the $file is always an (sub-)instance of \Core\File\Entity
137
     *
138
     * @param \Core\View\Helper\InsertFile\FileEvent $e
139
     * @return string
140
     */
141
    public function renderFile(FileEvent $e)
142
    {
143
        $file = $e->getLastFileObject();
144
        // assume it is of the class Core\Entity\FileEntity
145
        $return = '<div class="col-md-3"><a href="#attachment_' . $file->getId() . '">' . $file->getName() . '</a></div>' . PHP_EOL
146
                . '<div class="col-md-3">' . $file->getType() . '</div>'
147
                . '<div class="col-md-3">' . $file->prettySize . '</div>';
148
        /*
149
         * this snippet was for direct inserting an image into the PDF
150
        if ($file && $file instanceOf FileEntity && 0 === strpos($file->getType(), 'image')) {
151
            //$content = $file->getContent();
152
            //$url = 'data:image/' . $file->getType() . ';base64,' . base64_encode ($content);
153
            //$html = '<img src="' . $url . '" >';
154
            $html = '<a href="#1">' . $file->getName() . '</a>';
155
            $e->stopPropagation();
156
            return $html;
157
        }
158
         */
159
        return $return;
160
    }
161
162
    /**
163
     * give a summary of all inserted Files,
164
     * this is for having access to those files in the post-process
165
     * @param \Core\View\Helper\InsertFile\FileEvent|\Zend\View\ViewEvent $e
166
     * @return NULL
167
     */
168
    public function collectFiles(FileEvent $e)
169
    {
170
        $this->appendPDF = array();
171
        $files = $e->getAllFiles();
172
        foreach ($files as $name => $file) {
173
            if (!empty($file) && $file instanceof FileEntity) {
174
                if (0 === strpos($file->getType(), 'image')) {
175
                    $this->appendImage[] = $file;
176
                }
177
                if (strtolower($file->getType()) == 'application/pdf') {
178
                    $this->appendPDF[] = $file;
179
                }
180
            }
181
        }
182
        return null;
183
    }
184
    
185
    /**
186
     * remove unwanted or layout related data
187
     *
188
     * basically you rake through the viewmodel for the data you want to use for your template,
189
     * this may not be optimal because you have to rely on the correct naming of the viewmodels
190
     *
191
     * if you get the data you want, you switch to the specific template by adding the conforming resolver
192
     *
193
     * @param \Zend\View\ViewEvent $e
194
     */
195
    public function cleanLayout(ViewEvent $e)
196
    {
197
        $result   = $e->getResult();
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
198
        $response = $e->getResponse();
0 ignored issues
show
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
199
        $model = $e->getModel();
200
        if ($model->hasChildren()) {
201
            $children = $model->getChildren();
202
            $content = null;
203
            foreach ($children as $child) {
204
                if ($child->captureTo() == 'content') {
205
                    $content = $child;
206
                    $this->attachViewResolver();
207
                }
208
            }
209
            if (!empty($content)) {
210
                $e->setModel($content);
211
            }
212
        } else {
213
            // attach the own resolver here too ?
214
            // ...
215
        }
216
    }
217
    
218
    /**
219
     * Attach an own ViewResolver
220
     */
221
    public function attachViewResolver()
222
    {
223
        if (!$this->viewResolverAttached) {
224
            $this->viewResolverAttached = true;
225
            $resolver = $this->serviceManager->get('ViewResolver');
226
            $resolver->attach($this, 100);
227
        }
228
    }
229
    
230
    /**
231
     * Transform the HTML to PDF,
232
     * this is a post-rendering-process
233
     *
234
     * put in here everything related to the transforming-process like options
235
     *
236
     * @param \Zend\View\ViewEvent $e
237
     */
238
    public function attachPDFtransformer(ViewEvent $e)
239
    {
240
        
241
        //$renderer = $e->getRenderer();
242
        $result   = $e->getResult();
243
        $response = $e->getResponse();
0 ignored issues
show
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
244
        
245
        // the handles are for temporary files
246
        error_reporting(0);
247
        foreach (array(self::RENDER_FULL, self::RENDER_WITHOUT_PDF, self::RENDER_WITHOUT_ATTACHMENTS ) as $render) {
248
            $handles = array();
249
            try {
250
                $pdf = new extern\mPDFderive();
251
                $pdf->SetImportUse();
252
                // create bookmark list in Acrobat Reader
253
                $pdf->h2bookmarks = array('H1' => 0, 'H2' => 1, 'H3' => 2);
254
                $pdf->WriteHTML($result);
255
256
                // Output of the Images
257
                if (self::RENDER_FULL == $render || self::RENDER_WITHOUT_PDF == $render) {
258
                    if (is_array($this->appendImage) && !empty($this->appendImage)) {
259
                        foreach ($this->appendImage as $imageAttachment) {
260
                            $content = $imageAttachment->getContent();
261
                            $url = 'data:image/' . $imageAttachment->getType() . ';base64,' . base64_encode($content);
262
                            $html = '<a name="attachment_' . $imageAttachment->getId() . '"><img src="' . $url . '" /><br /></a>';
263
                            $pdf->WriteHTML($html);
264
                        }
265
                    }
266
                }
267
268
                // Temp Files PDF
269
                if (self::RENDER_FULL == $render) {
270
                    if (is_array($this->appendPDF) && !empty($this->appendPDF)) {
271
                        foreach ($this->appendPDF as $pdfAttachment) {
272
                            $content = $pdfAttachment->getContent();
273
                            $tmpHandle = tmpfile();
274
                            $handles[] = $tmpHandle;
275
                            fwrite($tmpHandle, $content);
0 ignored issues
show
Bug introduced by
It seems like $tmpHandle can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

275
                            fwrite(/** @scrutinizer ignore-type */ $tmpHandle, $content);
Loading history...
276
                            fseek($tmpHandle, 0);
0 ignored issues
show
Bug introduced by
It seems like $tmpHandle can also be of type false; however, parameter $handle of fseek() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

276
                            fseek(/** @scrutinizer ignore-type */ $tmpHandle, 0);
Loading history...
277
                        }
278
                    }
279
                }
280
281
                // Output of the PDF
282
                foreach ($handles as $handle) {
283
                    $meta_data = stream_get_meta_data($handle);
284
                    $filename = $meta_data["uri"];
285
                    $pdf->WriteHTML($filename);
286
                    $pagecount = $pdf->SetSourceFile($filename);
287
                    for ($pages = 0; $pages < $pagecount; $pages++) {
288
                        $pdf->AddPage();
289
                        $pdf->WriteHTML(' pages: ' . $pagecount);
290
                        $tx = $pdf->ImportPage($pages + 1);
291
                        $pdf->UseTemplate($tx);
292
                    }
293
                }
294
295
                $pdf_result = $pdf->Output();
296
                $e->setResult($pdf_result);
297
298
                // delete all temporary Files again
299
                foreach ($handles as $handle) {
300
                    fclose($handle);
301
                }
302
                break;
303
            } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
304
            }
305
        }
306
        error_reporting(E_ALL);
307
    }
308
    
309
    /**
310
     * Look for a template with the Suffix ".pdf.phtml"
311
     *
312
     * @param string $name
313
     * @param \Zend\View\Renderer\RendererInterface $renderer
314
     * @return string|boolean
315
     */
316
    public function resolve($name, Renderer $renderer = null)
317
    {
318
        if ($this->serviceManager->has('ViewTemplatePathStack')) {
319
            // get all the Pases made up for the zend-provided resolver
320
            // we won't get any closer to ALL than that
321
            $viewTemplatePathStack = $this->serviceManager->get('ViewTemplatePathStack');
322
            $paths = $viewTemplatePathStack->getPaths();
323
            $defaultSuffix = $viewTemplatePathStack->getDefaultSuffix();
324
            if (pathinfo($name, PATHINFO_EXTENSION) != $defaultSuffix) {
325
                ;
326
                $name .= '.pdf.' . $defaultSuffix;
327
            } else {
328
                // TODO: replace Filename by Filename for PDF
329
            }
330
331
            foreach ($paths as $path) {
332
                $file = new SplFileInfo($path . $name);
333
                if ($file->isReadable()) {
334
                    // Found! Return it.
335
                    if (($filePath = $file->getRealPath()) === false && substr($path, 0, 7) === 'phar://') {
336
                        // Do not try to expand phar paths (realpath + phars == fail)
337
                        $filePath = $path . $name;
338
                        if (!file_exists($filePath)) {
339
                            break;
340
                        }
341
                    }
342
                    //if ($this->useStreamWrapper()) {
343
                    //    // If using a stream wrapper, prepend the spec to the path
344
                    //    $filePath = 'zend.view://' . $filePath;
345
                    //}
346
                    return $filePath;
347
                }
348
            }
349
        }
350
        // TODO: Resolving to an PDF has failed, this could have implications for the transformer
351
        return false;
352
    }
353
}
354