Issues (2559)

app/Report/AbstractRenderer.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2025 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\Report;
21
22
use Fisharebest\Webtrees\I18N;
23
use Fisharebest\Webtrees\MediaFile;
24
use Fisharebest\Webtrees\Webtrees;
25
26
/**
27
 * Class AbstractRenderer - base for PDF and HTML reports
28
 */
29
abstract class AbstractRenderer
30
{
31
    // Reports layouts are measured in points.
32
    protected const string UNITS = 'pt';
0 ignored issues
show
A parse error occurred: Syntax error, unexpected T_STRING, expecting '=' on line 32 at column 27
Loading history...
33
34
    // A point is 1/72 of an inch
35
    protected const float INCH_TO_POINTS = 72.0;
36
    protected const float MM_TO_POINTS   = 72.0 / 25.4;
37
38
    protected const array PAPER_SIZES = [
39
        // ISO 216
40
        'A0'         => [841.0 * self::MM_TO_POINTS, 1189.0 * self::MM_TO_POINTS],
41
        'A1'         => [594.0 * self::MM_TO_POINTS, 841.0 * self::MM_TO_POINTS],
42
        'A2'         => [420.0 * self::MM_TO_POINTS, 594.0 * self::MM_TO_POINTS],
43
        'A3'         => [297.0 * self::MM_TO_POINTS, 420.0 * self::MM_TO_POINTS],
44
        'A4'         => [210.0 * self::MM_TO_POINTS, 297.0 * self::MM_TO_POINTS],
45
        // US
46
        'US-Letter'  => [8.5 * self::INCH_TO_POINTS, 11.0 * self::INCH_TO_POINTS],
47
        'US-Legal'   => [8.5 * self::INCH_TO_POINTS, 14.0 * self::INCH_TO_POINTS],
48
        'US-Tabloid' => [11.0 * self::INCH_TO_POINTS, 17.0 * self::INCH_TO_POINTS],
49
    ];
50
51
    public float $left_margin = 18.0 * self::MM_TO_POINTS;
52
53
    public float $right_margin = 9.9 * self::MM_TO_POINTS;
54
55
    public float $top_margin = 26.8 * self::MM_TO_POINTS;
56
57
    public float $bottom_margin = 21.6 * self::MM_TO_POINTS;
58
59
    public float $header_margin = 4.9 * self::MM_TO_POINTS;
60
61
    public float $footer_margin = 9.9 * self::MM_TO_POINTS;
62
63
    /** @var string Page orientation (portrait, landscape) */
64
    public string $orientation = 'portrait';
65
66
    /** @var string Page format name */
67
    public string $page_format = 'A4';
68
69
    /** @var float Height of page format in points */
70
    public float $page_height = 0.0;
71
72
    /** @var float Width of page format in points */
73
    public float $page_width = 0.0;
74
75
    /** @var array<array{'name': string, 'font': string, 'style': string, 'size': float}> Styles elements found in the document */
76
    public array $styles = [];
77
78
    /** @var string The default Report font name */
79
    public string $default_font = 'dejavusans';
80
81
    /** @var float The default Report font size */
82
    public float $default_font_size = 12.0;
83
84
    /** @var string Header (H), Body (B) or Footer (F) */
85
    public string $processing = 'H';
86
87
    /** @var bool RTL Language (false=LTR, true=RTL) */
88
    public bool $rtl = false;
89
90
    /** @var bool Show the Generated by... (true=show the text) */
91
    public bool $show_generated_by = true;
92
93
    /** @var string Generated By... text */
94
    public string $generated_by = '';
95
96
    /** @var string The report title */
97
    public string $title = '';
98
99
    /** @var string Author of the report, the users full name */
100
    public string $rauthor = Webtrees::NAME . ' ' . Webtrees::VERSION;
101
102
    /** @var string Keywords */
103
    public string $rkeywords = '';
104
105
    /** @var string Report Description / Subject */
106
    public string $rsubject = '';
107
108
    /** @var array<ReportBaseElement|string> */
109
    public array $headerElements = [];
110
111
    /** @var array<ReportBaseElement|string> */
112
    public array $footerElements = [];
113
114
    /** @var array<ReportBaseElement|string> */
115
    public array $bodyElements = [];
116
117
    public string $currentStyle = '';
118
119
    /**
120
     * Clear the Header.
121
     *
122
     * @return void
123
     */
124
    abstract public function clearHeader(): void;
125
126
    /**
127
     * @param ReportBaseElement|string $element
128
     *
129
     * @return void
130
     */
131
    public function addElement($element): void
132
    {
133
        if ($this->processing === 'B') {
134
            $this->addElementToBody($element);
135
        } elseif ($this->processing === 'H') {
136
            $this->addElementToHeader($element);
137
        } elseif ($this->processing === 'F') {
138
            $this->addElementToFooter($element);
139
        }
140
    }
141
142
    /**
143
     * @param ReportBaseElement|string $element
144
     *
145
     * @return void
146
     */
147
    public function addElementToHeader($element): void
148
    {
149
        $this->headerElements[] = $element;
150
    }
151
152
    /**
153
     * @param ReportBaseElement|string $element
154
     *
155
     * @return void
156
     */
157
    public function addElementToBody($element): void
158
    {
159
        $this->bodyElements[] = $element;
160
    }
161
162
    /**
163
     * @param ReportBaseElement|string $element
164
     *
165
     * @return void
166
     */
167
    public function addElementToFooter($element): void
168
    {
169
        $this->footerElements[] = $element;
170
    }
171
172
    /**
173
     * Run the report.
174
     *
175
     * @return void
176
     */
177
    abstract public function run(): void;
178
179
    /**
180
     * Create a new Cell object.
181
     *
182
     * @param float  $width   cell width (expressed in points)
183
     * @param float  $height  cell height (expressed in points)
184
     * @param string $border  Border style
185
     * @param string $align   Text alignment
186
     * @param string $bgcolor Background color code
187
     * @param string $style   The name of the text style
188
     * @param int    $ln      Indicates where the current position should go after the call
189
     * @param float  $top     Y-position
190
     * @param float  $left    X-position
191
     * @param bool   $fill    Indicates if the cell background must be painted (1) or transparent (0). Default value: 1
192
     * @param int    $stretch Stretch character mode
193
     * @param string $bocolor Border color
194
     * @param string $tcolor  Text color
195
     * @param bool   $reseth
196
     *
197
     * @return ReportBaseCell
198
     */
199
    abstract public function createCell(
200
        float $width,
201
        float $height,
202
        string $border,
203
        string $align,
204
        string $bgcolor,
205
        string $style,
206
        int $ln,
207
        float $top,
208
        float $left,
209
        bool $fill,
210
        int $stretch,
211
        string $bocolor,
212
        string $tcolor,
213
        bool $reseth
214
    ): ReportBaseCell;
215
216
    /**
217
     * Create a new TextBox object.
218
     *
219
     * @param float  $width   Text box width
220
     * @param float  $height  Text box height
221
     * @param bool   $border
222
     * @param string $bgcolor Background color code in HTML
223
     * @param bool   $newline
224
     * @param float  $left
225
     * @param float  $top
226
     * @param bool   $pagecheck
227
     * @param string $style
228
     * @param bool   $fill
229
     * @param bool   $padding
230
     * @param bool   $reseth
231
     *
232
     * @return ReportBaseTextbox
233
     */
234
    abstract public function createTextBox(
235
        float $width,
236
        float $height,
237
        bool $border,
238
        string $bgcolor,
239
        bool $newline,
240
        float $left,
241
        float $top,
242
        bool $pagecheck,
243
        string $style,
244
        bool $fill,
245
        bool $padding,
246
        bool $reseth
247
    ): ReportBaseTextbox;
248
249
    /**
250
     * Create a text element.
251
     *
252
     * @param string $style
253
     * @param string $color
254
     *
255
     * @return ReportBaseText
256
     */
257
    abstract public function createText(string $style, string $color): ReportBaseText;
258
259
    /**
260
     * Create a line.
261
     *
262
     * @param float $x1
263
     * @param float $y1
264
     * @param float $x2
265
     * @param float $y2
266
     *
267
     * @return ReportBaseLine
268
     */
269
    abstract public function createLine(float $x1, float $y1, float $x2, float $y2): ReportBaseLine;
270
271
    /**
272
     * Create a new image object.
273
     *
274
     * @param string $file  Filename
275
     * @param float  $x
276
     * @param float  $y
277
     * @param float  $w     Image width
278
     * @param float  $h     Image height
279
     * @param string $align L:left, C:center, R:right or empty to use x/y
280
     * @param string $ln    T:same line, N:next line
281
     *
282
     * @return ReportBaseImage
283
     */
284
    abstract public function createImage(string $file, float $x, float $y, float $w, float $h, string $align, string $ln): ReportBaseImage;
285
286
    /**
287
     * Create a new image object from Media Object.
288
     *
289
     * @param MediaFile          $media_file
290
     * @param float              $x
291
     * @param float              $y
292
     * @param float              $w     Image width
293
     * @param float              $h     Image height
294
     * @param string             $align L:left, C:center, R:right or empty to use x/y
295
     * @param string             $ln    T:same line, N:next line
296
     *
297
     * @return ReportBaseImage
298
     */
299
    abstract public function createImageFromObject(
300
        MediaFile $media_file,
301
        float $x,
302
        float $y,
303
        float $w,
304
        float $h,
305
        string $align,
306
        string $ln
307
    ): ReportBaseImage;
308
309
    /**
310
     * Create a new Footnote object.
311
     *
312
     * @param string $style Style name
313
     *
314
     * @return ReportBaseFootnote
315
     */
316
    abstract public function createFootnote(string $style): ReportBaseFootnote;
317
318
    /**
319
     * Initial Setup
320
     * Setting up document wide defaults that will be inherited of the report modules
321
     * As DEFAULT A4 and Portrait will be used if not set
322
     *
323
     * @return void
324
     */
325
    public function setup(): void
326
    {
327
        $this->rtl = I18N::direction() === 'rtl';
328
329
        $this->rkeywords = '';
330
331
        // I18N: This is a report footer. %s is the name of the application.
332
        $this->generated_by = I18N::translate('Generated by %s', Webtrees::NAME . ' ' . Webtrees::VERSION);
333
334
        // Paper size - defaults to A4 if the report fails to define a size.
335
        [$this->page_width, $this->page_height] = self::PAPER_SIZES[$this->page_format] ?? self::PAPER_SIZES['A4'];
336
    }
337
338
    /**
339
     * Process the Header, Body or Footer
340
     *
341
     * @param string $p Header (H), Body (B) or Footer (F)
342
     *
343
     * @return void
344
     */
345
    public function setProcessing(string $p): void
346
    {
347
        $this->processing = $p;
348
    }
349
350
    /**
351
     * Add the Title when raw character data is used in Title
352
     *
353
     * @param string $data
354
     *
355
     * @return void
356
     */
357
    public function addTitle(string $data): void
358
    {
359
        $this->title .= $data;
360
    }
361
362
    /**
363
     * Add the Description when raw character data is used in Description
364
     *
365
     * @param string $data
366
     *
367
     * @return void
368
     */
369
    public function addDescription(string $data): void
370
    {
371
        $this->rsubject .= $data;
372
    }
373
374
    /**
375
     * Add Style to Styles array
376
     *
377
     * @param array{'name': string, 'font': string, 'style': string, 'size': float} $style
378
     *
379
     * @return void
380
     */
381
    public function addStyle(array $style): void
382
    {
383
        $this->styles[$style['name']] = $style;
384
    }
385
386
    /**
387
     * Get a style from the Styles array
388
     *
389
     * @param string $s Style name
390
     *
391
     * @return array{'name': string, 'font': string, 'style': string, 'size': float}
392
     */
393
    public function getStyle(string $s): array
394
    {
395
        return $this->styles[$s];
396
    }
397
}
398