GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

PdfPrinceXmlPublisher::findPrinceXMLPath()   A
last analyzed

Complexity

Conditions 5
Paths 9

Size

Total Lines 25

Duplication

Lines 25
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 25
loc 25
ccs 0
cts 21
cp 0
rs 9.2088
c 0
b 0
f 0
cc 5
nc 9
nop 0
crap 30
1
<?php
2
3
/*
4
 * This file is part of the trefoil application.
5
 *
6
 * (c) Miguel Angel Gabriel <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Trefoil\Publishers;
13
14
use ZendPdf\PdfDocument;
15
16
/**
17
 * It publishes the book as a PDF file. All the internal links are transformed
18
 * into clickable cross-section book links. These links even display automatically
19
 * the page number where they point into, so no information is lost when printing
20
 * the book.
21
 */
22
class PdfPrinceXmlPublisher extends PdfPublisher
23
{
24
    public function checkIfThisPublisherIsSupported()
25
    {
26
        if (null !== $this->app['prince.path'] && file_exists($this->app['prince.path'])) {
27
            $princeXMLPath = $this->app['prince.path'];
28
        } else {
29
            $princeXMLPath = $this->findPrinceXMLPath();
30
        }
31
32
        $this->app['prince.path'] = $princeXMLPath;
33
34
        return null !== $princeXMLPath && file_exists($princeXMLPath);
35
    }
36
37
    public function assembleBook()
38
    {
39
        // reuse output temp dir for easy debugging and to avoid polluting the cache dir
40
        $tmpDir = $this->app['app.dir.cache'] . '/easybook_pdf';
41
        if ($this->app['filesystem']->exists($tmpDir)) {
42
            $this->app['filesystem']->remove($tmpDir);
43
        }
44
        $this->app['filesystem']->mkdir($tmpDir);
45
46
        // consolidate book images to temp dir
47
        $imagesDir = $tmpDir . '/images';
48
        if (!$this->app['filesystem']->exists($imagesDir)) {
49
            $this->app['filesystem']->mkdir($imagesDir);
50
        }
51
        $this->prepareBookImages($imagesDir);
52
        $this->prepareBookCoverImage($imagesDir);
53
54
        // implode all the contents to create the whole book
55
        $htmlBookFilePath = $tmpDir . '/book.html';
56
        $this->app->render(
57
            'book.twig',
58
            array('items' => $this->app['publishing.items']),
59
            $htmlBookFilePath
60
        );
61
62
        // use PrinceXML to transform the HTML book into a PDF book
63
        $prince = $this->app['prince'];
64
        $prince->setBaseURL($imagesDir);
65
66
        // Prepare and add stylesheets before PDF conversion
67 View Code Duplication
        if ($this->app->edition('include_styles')) {
68
            $defaultStyles = $tmpDir . '/default_styles.css';
69
            $this->app->render(
70
                '@theme/style.css.twig',
71
                array('resources_dir' => $this->app['app.dir.resources'] . '/'),
72
                $defaultStyles
73
            );
74
75
            $prince->addStyleSheet($defaultStyles);
76
        }
77
78
        $customCss = $this->getCustomCssFile();
79
        if (file_exists($customCss)) {
80
            $prince->addStyleSheet($customCss);
81
        }
82
83
        $errorMessages = array();
84
        $pdfBookFilePath = $this->app['publishing.dir.output'] . '/book.pdf';
85
        $prince->convert_file_to_file($htmlBookFilePath, $pdfBookFilePath, $errorMessages);
86
        $this->displayPdfConversionErrors($errorMessages);
87
88
        $this->addBookCover($pdfBookFilePath, $this->getCustomCover());
89
    }
90
91
    /**
92
     * Looks for the executable of the PrinceXML library.
93
     *
94
     * @return string The absolute path of the executable
95
     *
96
     * @throws \RuntimeException If the PrinceXML executable is not found
97
     */
98 View Code Duplication
    public function findPrinceXMLPath()
99
    {
100
        foreach ($this->app['prince.default_paths'] as $path) {
101
            if (file_exists($path)) {
102
                return $path;
103
            }
104
        }
105
106
        // the executable couldn't be found in the common
107
        // installation directories. Ask the user for the path
108
        $isInteractive = null !== $this->app['console.input'] && $this->app['console.input']->isInteractive();
109
        if ($isInteractive) {
110
            return $this->askForPrinceXMLPath();
111
        }
112
113
        throw new \RuntimeException(
114
            sprintf(
115
                "ERROR: The PrinceXML library needed to generate PDF books cannot be found.\n"
116
                . " Check that you have installed PrinceXML in a common directory \n"
117
                . " or set your custom PrinceXML path in the book's config.yml file:\n\n"
118
                . '%s',
119
                $this->getSampleYamlConfiguration()
120
            )
121
        );
122
    }
123
124 View Code Duplication
    public function askForPrinceXMLPath()
125
    {
126
        $this->app['console.output']->write(
127
            sprintf(
128
                " In order to generate PDF files, PrinceXML library must be installed. \n\n"
129
                . " We couldn't find PrinceXML executable in any of the following directories: \n"
130
                . "   -> %s \n\n"
131
                . " If you haven't installed it yet, you can download a fully-functional demo at: \n"
132
                . " %s \n\n"
133
                . " If you have installed in a custom directory, please type its full absolute path:\n > ",
134
                implode($this->app['prince.default_paths'], "\n   -> "),
135
                'http://www.princexml.com/download'
136
            )
137
        );
138
139
        $userGivenPath = trim(fgets(STDIN));
140
141
        // output a newline for aesthetic reasons
142
        $this->app['console.output']->write("\n");
143
144
        return $userGivenPath;
145
    }
146
147
    /**
148
     * It displays the error messages generated by the PDF conversion
149
     * process in a user-friendly way.
150
     *
151
     * @param array $errorMessages The array of messages generated by PrinceXML
152
     */
153
    public function displayPdfConversionErrors($errorMessages)
154
    {
155
        if (count($errorMessages) > 0) {
156
            $this->app['console.output']->writeln("\n PrinceXML errors and warnings");
157
            $this->app['console.output']->writeln(" -----------------------------\n");
158
159
            foreach ($errorMessages as $message) {
160
                $this->app['console.output']->writeln(
161
                    '   [' . strtoupper($message[0]) . '] ' . ucfirst($message[2]) . ' (' . $message[1] . ')'
162
                );
163
            }
164
165
            $this->app['console.output']->writeln("\n");
166
        }
167
    }
168
169
    /**
170
     * It prepares the book cover image (if the book defines one).
171
     *
172
     * @param string $targetDir The directory where the cover image is copied.
173
     *
174
     * @return array|null Book cover image data or null if the book doesn't
175
     *                    include a cover image.
176
     */
177 View Code Duplication
    private function prepareBookCoverImage($targetDir)
178
    {
179
        $cover = null;
180
181
        if (null !== $image = $this->app->getCustomCoverImage()) {
182
            list($width, $height, $type) = getimagesize($image);
183
184
            $cover = array(
185
                'height'    => $height,
186
                'width'     => $width,
187
                'filePath'  => 'images/' . basename($image),
188
                'mediaType' => image_type_to_mime_type($type)
189
            );
190
191
            $this->app['filesystem']->copy($image, $targetDir . '/' . basename($image));
192
        }
193
194
        return $cover;
195
    }
196
197
    /**
198
     * If the book defines a custom PDF cover, this method prepends it
199
     * to the PDF book.
200
     *
201
     * @param string $bookFilePath  The path of the original PDF book without the cover
202
     * @param string $coverFilePath The path of the PDF file which will be displayed as the cover of the book
203
     */
204 View Code Duplication
    public function addBookCover($bookFilePath, $coverFilePath)
205
    {
206
        if (!empty($coverFilePath)) {
207
            $pdfBook = PdfDocument::load($bookFilePath);
208
            $pdfCover = PdfDocument::load($coverFilePath);
209
210
            $pdfCover = clone $pdfCover->pages[0];
211
            array_unshift($pdfBook->pages, $pdfCover);
212
213
            $pdfBook->save($bookFilePath, true);
214
        }
215
    }
216
217
    /*
218
     * It looks for custom book cover PDF. The search order is:
219
     *   1. <book>/Resources/Templates/<edition-name>/cover.pdf
220
     *   2. <book>/Resources/Templates/pdf/cover.pdf
221
     *   3. <book>/Resources/Templates/cover.pdf
222
     *
223
     * @param string $coverFileName The name of the PDF file that defines the book cover
224
     *
225
     * @return null|string The filePath of the PDF cover or null if none exists
226
     */
227 View Code Duplication
    public function getCustomCover($coverFileName = 'cover.pdf')
228
    {
229
        $paths = array(
230
            $this->app['publishing.dir.templates'] . '/' . $this->app['publishing.edition'],
231
            $this->app['publishing.dir.templates'] . '/pdf',
232
            $this->app['publishing.dir.templates'],
233
        );
234
235
        return $this->app->getFirstExistingFile($coverFileName, $paths);
236
    }
237
238
    /**
239
     * It returns the needed configuration to set up the custom PrinceXML path
240
     * using YAML format.
241
     *
242
     * @return string The sample YAML configuration
243
     */
244
    private function getSampleYamlConfiguration()
245
    {
246
        return <<<YAML
247
  easybook:
248
      parameters:
249
          prince.path: '/path/to/utils/PrinceXML/prince'
250
251
  book:
252
      title:  ...
253
      author: ...
254
      # ...
255
YAML;
256
    }
257
}
258