Passed
Pull Request — main (#4128)
by David
06:31
created

Note::getHtml()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 11
nc 4
nop 0
dl 0
loc 23
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2021 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;
21
22
use Fisharebest\Webtrees\Http\RequestHandlers\NotePage;
23
use Illuminate\Database\Capsule\Manager as DB;
24
25
use function explode;
26
use function htmlspecialchars_decode;
27
use function preg_match;
28
use function preg_replace;
29
use function strip_tags;
30
use function trim;
31
32
use const ENT_QUOTES;
33
34
/**
35
 * A GEDCOM note (NOTE) object.
36
 */
37
class Note extends GedcomRecord
38
{
39
    public const RECORD_TYPE = 'NOTE';
40
41
    protected const ROUTE_NAME = NotePage::class;
42
43
    private const NAME_LENGTH = 75;
44
45
    /**
46
     * Get the text contents of the note
47
     *
48
     * @return string
49
     */
50
    public function getNote(): string
51
    {
52
        if (preg_match('/^0 @' . Gedcom::REGEX_XREF . '@ NOTE ?(.*(?:\n1 CONT ?.*)*)/', $this->gedcom . $this->pending, $match)) {
53
            return preg_replace("/\n1 CONT ?/", "\n", $match[1]);
54
        }
55
56
        return '';
57
    }
58
59
    /**
60
     * Get the contents of the note formatted according to the tree option
61
     *
62
     * @return string
63
     */
64
    public function getHtml()
65
    {
66
        $text = $this->getNote();
67
        if ($text === '') {
68
            return $text;
69
        }
70
71
        // Obey FORMAT_TEXT option strictly. To restore previous behaviour whereby
72
        // text containing markdown tables is always interpreted as markdown
73
        // uncomment the end of the next line
74
        if ($this->tree()->getPreference('FORMAT_TEXT') === 'markdown') { // || preg_match('/\| ? -{3,}/', $text) === 1) {
75
            $paragraphs = '';
76
            // Split on "\n" except where the line is part of a markdown table (starts and ends with |)
77
            $note_paras = preg_split('/(?<!^\|)(?<!\|)\n/', $text);
78
            if ($note_paras !== false) {
79
                foreach (array_filter($note_paras) as $note_para) {
80
                    $paragraphs .= Registry::markdownFactory()->markdown($this->tree())->convertToHtml($note_para);
81
                }
82
            }
83
            return '<div class="markdown">' . $paragraphs . '</div>';
84
        }
85
86
        return '<div>' . nl2br($text) . '</div>';
87
    }
88
89
    /**
90
     * Each object type may have its own special rules, and re-implement this function.
91
     *
92
     * @param int $access_level
93
     *
94
     * @return bool
95
     */
96
    protected function canShowByType(int $access_level): bool
97
    {
98
        // Hide notes if they are attached to private records
99
        $linked_ids = DB::table('link')
100
            ->where('l_file', '=', $this->tree->id())
101
            ->where('l_to', '=', $this->xref)
102
            ->pluck('l_from');
103
104
        foreach ($linked_ids as $linked_id) {
105
            $linked_record = Registry::gedcomRecordFactory()->make($linked_id, $this->tree);
106
            if ($linked_record instanceof GedcomRecord && !$linked_record->canShow($access_level)) {
107
                return false;
108
            }
109
        }
110
111
        // Apply default behavior
112
        return parent::canShowByType($access_level);
113
    }
114
115
    /**
116
     * Create a name for this note - apply (and remove) markup, then take
117
     * a maximum of NAME_LENGTH characters from the first non-empty line.
118
     *
119
     * @return void
120
     */
121
    public function extractNames(): void
122
    {
123
        if ($this->tree->getPreference('FORMAT_TEXT') === 'markdown') {
124
            $text = Registry::markdownFactory()->markdown()->convertToHtml($this->getNote());
125
        } else {
126
            $text = Registry::markdownFactory()->autolink()->convertToHtml($this->getNote());
127
        }
128
129
130
        // Take the first line
131
        [$text] = explode("\n", strip_tags(trim($text)));
132
133
134
        if ($text !== '') {
135
            $text = htmlspecialchars_decode($text, ENT_QUOTES | ENT_SUBSTITUTE);
136
            if (mb_strlen($text) >= self::NAME_LENGTH) {
137
                // truncate $text to words closest to NAME_LENGTH
138
                $last_space = (int) mb_strrpos(mb_substr($text, 0, self::NAME_LENGTH), " ", 0);
139
                $text = mb_substr($text, 0, $last_space) . I18N::translate('…');
140
            }
141
142
            $this->addName('NOTE', $text, $this->gedcom());
143
        }
144
    }
145
}
146