Completed
Push — 2.1 ( a48c6e...94265a )
by Greg
06:30
created

AbstractElement   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 246
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 56
c 1
b 0
f 0
dl 0
loc 246
rs 10
wmc 20

14 Methods

Rating   Name   Duplication   Size   Complexity  
A editHidden() 0 3 1
A canonical() 0 9 2
A editTextArea() 0 3 1
A edit() 0 25 3
A __construct() 0 4 1
A default() 0 3 1
A label() 0 3 1
A subtags() 0 3 1
A labelValue() 0 7 1
A escape() 0 3 1
A valueNumeric() 0 9 2
A valueAutoLink() 0 17 1
A value() 0 15 3
A values() 0 3 1
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2020 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 <http://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\GedcomElements;
21
22
use Fisharebest\Webtrees\I18N;
23
use Fisharebest\Webtrees\Tree;
24
use League\CommonMark\Block\Element\Document;
25
use League\CommonMark\Block\Element\Paragraph;
26
use League\CommonMark\Block\Renderer\DocumentRenderer;
27
use League\CommonMark\Block\Renderer\ParagraphRenderer;
28
use League\CommonMark\CommonMarkConverter;
29
use League\CommonMark\Environment;
30
use League\CommonMark\Inline\Element\Link;
31
use League\CommonMark\Inline\Element\Text;
32
use League\CommonMark\Inline\Parser\AutolinkParser;
33
use League\CommonMark\Inline\Renderer\LinkRenderer;
34
use League\CommonMark\Inline\Renderer\TextRenderer;
35
36
use function array_key_exists;
37
use function array_map;
38
use function array_splice;
39
use function asort;
40
use function e;
41
use function is_numeric;
42
use function preg_replace;
43
use function strpos;
44
use function trim;
45
use function view;
46
47
/**
48
 * A GEDCOM element is a tag/primitive in a GEDCOM file.
49
 */
50
abstract class AbstractElement implements GedcomElementInterface
51
{
52
    private const REGEX_URL = '~((https?|ftp]):)(//([^\s/?#<>]*))?([^\s?#<>]*)(\?([^\s#<>]*))?(#[^\s?#<>]+)?~';
53
54
    // Which child elements can appear under this element.
55
    protected const SUBTAGS = [];
56
57
    /** @var string A label to describe this element */
58
    private $label;
59
60
    /** @var array<string,string> */
61
    private $subtags;
62
63
    /**
64
     * AbstractGedcomElement constructor.
65
     *
66
     * @param string             $label
67
     * @param array<string>|null $subtags
68
     */
69
    public function __construct(string $label, array $subtags = null)
70
    {
71
        $this->label   = $label;
72
        $this->subtags = $subtags ?? static::SUBTAGS;
73
    }
74
75
    /**
76
     * Convert a value to a canonical form.
77
     *
78
     * @param string $value
79
     *
80
     * @return string
81
     */
82
    public function canonical(string $value): string
83
    {
84
        $value = strtr($value, ["\t" => ' ', "\r" => ' ', "\n" => ' ']);
85
86
        while (strpos($value, '  ') !== false) {
87
            $value = strtr($value, ['  ' => ' ']);
88
        }
89
90
        return trim($value);
91
    }
92
93
    /**
94
     * Create a default value for this element.
95
     *
96
     * @param Tree $tree
97
     *
98
     * @return string
99
     */
100
    public function default(Tree $tree): string
101
    {
102
        return '';
103
    }
104
105
    /**
106
     * An edit control for this data.
107
     *
108
     * @param string $id
109
     * @param string $name
110
     * @param string $value
111
     * @param Tree   $tree
112
     *
113
     * @return string
114
     */
115
    public function edit(string $id, string $name, string $value, Tree $tree): string
116
    {
117
        $values = $this->values();
118
119
        if ($values !== []) {
120
            asort($values);
121
            $value = $this->canonical($value);
122
123
            // Ensure the current data is in the list.
124
            if (!array_key_exists($value, $values)) {
125
                array_splice($values, 1, 0, [$value => $value]);
126
            }
127
128
            // We may use markup to display values, but not when editing them.
129
            $values = array_map('strip_tags', $values);
130
131
            return view('components/select', [
132
                'id'       => $id,
133
                'name'     => $name,
134
                'options'  => $values,
135
                'selected' => $value,
136
            ]);
137
        }
138
139
        return '<input class="form-control" type="text" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">';
140
    }
141
142
    /**
143
     * An edit control for this data.
144
     *
145
     * @param string $id
146
     * @param string $name
147
     * @param string $value
148
     *
149
     * @return string
150
     */
151
    public function editHidden(string $id, string $name, string $value): string
152
    {
153
        return '<input class="form-control" type="hidden" id="' . e($id) . '" name="' . e($name) . '" value="' . e($value) . '">';
154
    }
155
156
    /**
157
     * An edit control for this data.
158
     *
159
     * @param string $id
160
     * @param string $name
161
     * @param string $value
162
     *
163
     * @return string
164
     */
165
    public function editTextArea(string $id, string $name, string $value): string
166
    {
167
        return '<textarea class="form-control" id="' . e($id) . '" name="' . e($name) . '" rows="5" dir="auto">' . e($value) . '</textarea>';
168
    }
169
170
    /**
171
     * Escape @ signs in a GEDCOM export.
172
     *
173
     * @param string $value
174
     *
175
     * @return string
176
     */
177
    public function escape(string $value): string
178
    {
179
        return strtr($value, ['@' => '@@']);
180
    }
181
182
    /**
183
     * Create a label for this element.
184
     *
185
     * @return string
186
     */
187
    public function label(): string
188
    {
189
        return $this->label;
190
    }
191
192
    /**
193
     * Create a label/value pair for this element.
194
     *
195
     * @param string $value
196
     * @param Tree   $tree
197
     *
198
     * @return string
199
     */
200
    public function labelValue(string $value, Tree $tree): string
201
    {
202
        $label = '<span class="label">' . $this->label() . '</span>';
203
        $value = '<span class="value">' . $this->value($value, $tree) . '</span>';
204
        $html  = I18N::translate(/* I18N: e.g. "Occupation: farmer" */ '%1$s: %2$s', $label, $value);
205
206
        return '<div>' . $html . '</div>';
207
    }
208
209
    /**
210
     * @param Tree $tree
211
     *
212
     * @return array<string,string>
213
     */
214
    public function subtags(Tree $tree): array
215
    {
216
        return $this->subtags;
217
    }
218
219
    /**
220
     * Display the value of this type of element.
221
     *
222
     * @param string $value
223
     * @param Tree   $tree
224
     *
225
     * @return string
226
     */
227
    public function value(string $value, Tree $tree): string
228
    {
229
        $values = $this->values();
230
231
        if ($values === []) {
232
            if (str_contains($value, "\n")) {
233
                return '<span dir="auto" class="d-block" style="white-space: pre-wrap;">' . e($value) . '</span>';
234
            }
235
236
            return '<span dir="auto">' . e($value) . '</span>';
237
        }
238
239
        $canonical = $this->canonical($value);
240
241
        return $values[$canonical] ?? '<span dir="auto">' . e($value) . '</span>';
242
    }
243
244
    /**
245
     * A list of controlled values for this element
246
     *
247
     * @return array<int|string,string>
248
     */
249
    public function values(): array
250
    {
251
        return [];
252
    }
253
254
    /**
255
     * Display the value of this type of element - convert URLs to links
256
     *
257
     * @param string $value
258
     *
259
     * @return string
260
     */
261
    protected function valueAutoLink(string $value): string
262
    {
263
        // Convert URLs into markdown auto-links.
264
        $value = preg_replace(self::REGEX_URL, '<$0>', $value);
265
266
        // Create a minimal commonmark processor - just add support for autolinks.
267
        $environment = new Environment();
268
        $environment
269
            ->addBlockRenderer(Document::class, new DocumentRenderer())
270
            ->addBlockRenderer(Paragraph::class, new ParagraphRenderer())
271
            ->addInlineRenderer(Text::class, new TextRenderer())
272
            ->addInlineRenderer(Link::class, new LinkRenderer())
273
            ->addInlineParser(new AutolinkParser());
274
275
        $converter = new CommonMarkConverter(['html_input' => Environment::HTML_INPUT_ESCAPE], $environment);
276
277
        return $converter->convertToHtml($value);
278
    }
279
280
    /**
281
     * Display the value of this type of element.
282
     *
283
     * @param string $value
284
     *
285
     * @return string
286
     */
287
    public function valueNumeric(string $value): string
288
    {
289
        $canonical = $this->canonical($value);
290
291
        if (is_numeric($canonical)) {
292
            return I18N::number((int) $canonical);
293
        }
294
295
        return e($value);
296
    }
297
}
298