Passed
Pull Request — main (#5145)
by
unknown
08:43 queued 01:10
created

UidParser::firstMatchingUidRecord()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
c 0
b 0
f 0
nc 3
nop 2
dl 0
loc 11
rs 10
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\CommonMark;
21
22
use Fisharebest\Webtrees\Auth;
0 ignored issues
show
Bug introduced by
The type Fisharebest\Webtrees\Auth was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use Fisharebest\Webtrees\Gedcom;
24
use Fisharebest\Webtrees\GedcomRecord;
0 ignored issues
show
Bug introduced by
The type Fisharebest\Webtrees\GedcomRecord was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use Fisharebest\Webtrees\Registry;
26
use Fisharebest\Webtrees\Tree;
27
use Fisharebest\Webtrees\Services\GedcomImportService;
28
use Fisharebest\Webtrees\Services\TreeService;
0 ignored issues
show
Bug introduced by
The type Fisharebest\Webtrees\Services\TreeService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
use Fisharebest\Webtrees\Services\SearchService;
0 ignored issues
show
Bug introduced by
The type Fisharebest\Webtrees\Services\SearchService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use League\CommonMark\Parser\Inline\InlineParserInterface;
31
use League\CommonMark\Parser\Inline\InlineParserMatch;
32
use League\CommonMark\Parser\InlineParserContext;
33
use Illuminate\Support\Collection;
34
35
/**
36
 * Convert UIDs within markdown text to links
37
 */
38
class UidParser implements InlineParserInterface
39
{
40
    private Tree $tree;
41
    private SearchService $search_service;
42
43
    /**
44
     * @param Tree $tree Match UIDs in this tree
45
     */
46
    public function __construct(Tree $tree)
47
    {
48
        $this->tree = $tree;
49
        $this->search_service = new SearchService(new TreeService(new GedcomImportService($this->tree)));
0 ignored issues
show
Unused Code introduced by
The call to Fisharebest\Webtrees\Ser...tService::__construct() has too many arguments starting with $this->tree. ( Ignorable by Annotation )

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

49
        $this->search_service = new SearchService(new TreeService(/** @scrutinizer ignore-call */ new GedcomImportService($this->tree)));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
50
    }
51
52
    /**
53
     * We are only interested in text that begins with '@'.
54
     *
55
     * @return InlineParserMatch
56
     */
57
    public function getMatchDefinition(): InlineParserMatch
58
    {
59
        #This one permits escaping a # sign inside the text to be shown in the link and is ungreedy
60
        # so there can be more than one reference in one line
61
        return InlineParserMatch::regex('#(' . Gedcom::REGEX_UID . ')(?::(.*(?:(?!\\#).)*?))?#');
62
63
        // TESTED IN PHP 7.4
64
        //
65
        // #                  literal # (start ancor)
66
        // (                  start 1st capturing group
67
        // Gedcom::REGEX_UID  regex to match an UID
68
        // )                  end 1st capturing group
69
        // (?:                begin 1st non-capturing group
70
        //   :                a literal :
71
        //   (                start 2nd capturing group (without first :)
72
        //     .*             any character zero or more times
73
        //     (?:            begin 2nd non-capturing group
74
        //       (?!          begin negative lookahead
75
        //         \\#        literal text sequence \#
76
        //       )            end negative lookahead
77
        //       .            any single character   <- consumes one character if not followed by \#
78
        //     )              end 2nd non-capturing group
79
        //     *?             repeat 0 or more times 2nd non-capturing group NON GREEDY <- all characters before last # permiting \#
80
        //   )                end 2nd capturing group
81
        // )                  end 1st non-capturing group
82
        // ?                  2nd capturing group can be there or not
83
        // #                  literal # (end ancor)
84
    }
85
86
    private function firstMatchingUidRecord(String $pUid, Collection $pCollection): ?Object
87
    {
88
        foreach ($pCollection as $recTmp) {
89
            $regexTmp = '/\n1 _?UID ' . $pUid . '(:?\n|$)/';
90
            if (preg_match($regexTmp, $recTmp->gedcom())) {
91
                return $recTmp;
92
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
93
            }
94
        }
95
96
        return null;
97
    }
98
99
    /**
100
     * @param InlineParserContext $inlineContext
101
     *
102
     * @return bool
103
     */
104
    public function parse(InlineParserContext $inlineContext): bool
105
    {
106
        $cursor = $inlineContext->getCursor();
107
        $subm = $inlineContext->getSubMatches();
108
        $uid = [$subm[0]];
109
        $firstFoundRecord = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $firstFoundRecord is dead and can be removed.
Loading history...
110
        if (isset($subm[1])) {
111
            #Unescape character's #
112
113
            #NOTE: It should use only one \\, but it's using two because it get's escaped again in the regex processing.
114
            $linkText = preg_replace("/\\\\#/", "#", $subm[1]);
115
        } else {
116
            $linkText = '';
117
        }
118
119
        // Do the search
120
        $result = new Collection();
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
121
122
        // Log search requests for visitors
123
        if (Auth::id() === null) {
124
            Log::addSearchLog('General: ' . $query, $search_trees->all());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $query seems to be never defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable $search_trees seems to be never defined.
Loading history...
Bug introduced by
The type Fisharebest\Webtrees\CommonMark\Log was not found. Did you mean Log? If so, make sure to prefix the type with \.
Loading history...
125
        }
126
127
        $result = $this->search_service->searchIndividuals([$this->tree], $uid);
128
        $firstFoundRecord = $this->firstMatchingUidRecord($uid[0], $result);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $firstFoundRecord is correct as $this->firstMatchingUidRecord($uid[0], $result) targeting Fisharebest\Webtrees\Com...irstMatchingUidRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
129
130
        if ($firstFoundRecord === null) {
0 ignored issues
show
introduced by
The condition $firstFoundRecord === null is always true.
Loading history...
131
            $result = $this->search_service->searchFamilies([$this->tree], $uid);
132
            $firstFoundRecord = $this->firstMatchingUidRecord($uid[0], $result);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $firstFoundRecord is correct as $this->firstMatchingUidRecord($uid[0], $result) targeting Fisharebest\Webtrees\Com...irstMatchingUidRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
133
134
            if ($firstFoundRecord === null) {
0 ignored issues
show
introduced by
The condition $firstFoundRecord === null is always true.
Loading history...
135
                $result = $this->search_service->searchFamilyNames([$this->tree], $uid);
136
                $firstFoundRecord = $this->firstMatchingUidRecord($uid[0], $result);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $firstFoundRecord is correct as $this->firstMatchingUidRecord($uid[0], $result) targeting Fisharebest\Webtrees\Com...irstMatchingUidRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
137
138
                if ($firstFoundRecord === null) {
0 ignored issues
show
introduced by
The condition $firstFoundRecord === null is always true.
Loading history...
139
                    $result = $this->search_service->searchRepositories([$this->tree], $uid);
140
                    $firstFoundRecord = $this->firstMatchingUidRecord($uid[0], $result);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $firstFoundRecord is correct as $this->firstMatchingUidRecord($uid[0], $result) targeting Fisharebest\Webtrees\Com...irstMatchingUidRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
141
142
                    if ($firstFoundRecord === null) {
0 ignored issues
show
introduced by
The condition $firstFoundRecord === null is always true.
Loading history...
143
                        $result = $this->search_service->searchSources([$this->tree], $uid);
144
                        $firstFoundRecord = $this->firstMatchingUidRecord($uid[0], $result);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $firstFoundRecord is correct as $this->firstMatchingUidRecord($uid[0], $result) targeting Fisharebest\Webtrees\Com...irstMatchingUidRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
145
146
                        if ($firstFoundRecord === null) {
0 ignored issues
show
introduced by
The condition $firstFoundRecord === null is always true.
Loading history...
147
                            $result = $this->search_service->searchNotes([$this->tree], $uid);
148
                            $firstFoundRecord = $this->firstMatchingUidRecord($uid[0], $result);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $firstFoundRecord is correct as $this->firstMatchingUidRecord($uid[0], $result) targeting Fisharebest\Webtrees\Com...irstMatchingUidRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
149
150
                            if ($firstFoundRecord === null) {
0 ignored issues
show
introduced by
The condition $firstFoundRecord === null is always true.
Loading history...
151
                                $result = $this->search_service->searchLocations([$this->tree], $uid);
152
                                $firstFoundRecord = $this->firstMatchingUidRecord($uid[0], $result);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $firstFoundRecord is correct as $this->firstMatchingUidRecord($uid[0], $result) targeting Fisharebest\Webtrees\Com...irstMatchingUidRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
153
154
                                if ($firstFoundRecord === null) {
0 ignored issues
show
introduced by
The condition $firstFoundRecord === null is always true.
Loading history...
155
                                    $result = $this->search_service->searchMedia([$this->tree], $uid);
156
                                    $firstFoundRecord = $this->firstMatchingUidRecord($uid[0], $result);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $firstFoundRecord is correct as $this->firstMatchingUidRecord($uid[0], $result) targeting Fisharebest\Webtrees\Com...irstMatchingUidRecord() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
157
                                }
158
                            }
159
                        }
160
                    }
161
                }
162
            }
163
        }
164
165
        if ($firstFoundRecord === null) {
0 ignored issues
show
introduced by
The condition $firstFoundRecord === null is always true.
Loading history...
166
            return false;
167
        } else {
168
            $record = $firstFoundRecord;
169
170
            if ($record instanceof GedcomRecord) {
171
                $cursor->advanceBy($inlineContext->getFullMatchLength());
172
173
                $inlineContext->getContainer()->appendChild(new UidNode($record, $linkText));
174
175
                return true;
176
            }
177
178
            return false;
179
        }
180
    }
181
}
182