Passed
Push — master ( d0265c...1b1a87 )
by MusikAnimal
07:34
created

Blame::searchTokens()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 28
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 5.0291

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 18
c 1
b 0
f 0
nc 7
nop 1
dl 0
loc 28
ccs 17
cts 19
cp 0.8947
crap 5.0291
rs 9.3554
1
<?php
2
declare(strict_types = 1);
3
4
namespace AppBundle\Model;
5
6
/**
7
 * A Blame will search the given page for the given text and return the relevant revisions and authors.
8
 */
9
class Blame extends Authorship
10
{
11
    /** @var string Text to search for. */
12
    protected $query;
13
14
    /** @var array|null Matches, keyed by revision ID, each with keys 'edit' <Edit> and 'tokens' <string[]>. */
15
    protected $matches;
16
17
    /**
18
     * Blame constructor.
19
     * @param Page $page The page to process.
20
     * @param string $query Text to search for.
21
     * @param string|null $target Either a revision ID or date in YYYY-MM-DD format. Null to use latest revision.
22
     */
23 2
    public function __construct(Page $page, string $query, ?string $target = null)
24
    {
25 2
        parent::__construct($page, $target);
26
27 2
        $this->query = $query;
28 2
    }
29
30
    /**
31
     * Get the search query.
32
     * @return string
33
     */
34 1
    public function getQuery(): string
35
    {
36 1
        return $this->query;
37
    }
38
39
    /**
40
     * Matches, keyed by revision ID, each with keys 'edit' <Edit> and 'tokens' <string[]>.
41
     * @return array|null
42
     */
43 1
    public function getMatches(): ?array
44
    {
45 1
        return $this->matches;
46
    }
47
48
    /**
49
     * Strip out spaces, since they are not accounted for in the WikiWho API.
50
     * @return string
51
     */
52 2
    public function getTokenizedQuery(): string
53
    {
54 2
        return strtolower(preg_replace('/\s*/m', '', $this->query));
55
    }
56
57
    /**
58
     * Get authorship attribution from the WikiWho API.
59
     * @see https://f-squared.org/wikiwho/
60
     */
61 1
    public function prepareData(): void
62
    {
63 1
        if (isset($this->matches)) {
64
            return;
65
        }
66
67
        // Set revision data. self::setRevisionData() returns null if there are errors.
68 1
        $revisionData = $this->getRevisionData(true);
69 1
        if (null === $revisionData) {
70
            return;
71
        }
72
73 1
        $matches = $this->searchTokens($revisionData['tokens']);
74
75
        // We want the results grouped by editor and revision ID.
76 1
        $this->matches = [];
77 1
        foreach ($matches as $match) {
78 1
            if (isset($this->matches[$match['id']])) {
79 1
                $this->matches[$match['id']]['tokens'][] = $match['token'];
80 1
                continue;
81
            }
82
83 1
            $edit = $this->getRepository()->getEditFromRevId($this->page, $match['id']);
0 ignored issues
show
Bug introduced by
The method getEditFromRevId() does not exist on AppBundle\Repository\Repository. It seems like you code against a sub-type of AppBundle\Repository\Repository such as AppBundle\Repository\BlameRepository. ( Ignorable by Annotation )

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

83
            $edit = $this->getRepository()->/** @scrutinizer ignore-call */ getEditFromRevId($this->page, $match['id']);
Loading history...
84 1
            $this->matches[$match['id']] = [
85 1
                'edit' => $edit,
86 1
                'tokens' => [$match['token']],
87
            ];
88
        }
89 1
    }
90
91
    /**
92
     * @param array $tokens
93
     * @return array
94
     */
95 1
    private function searchTokens(array $tokens): array
96
    {
97 1
        $matchData = [];
98 1
        $matchDataSoFar = [];
99 1
        $matchSoFar = '';
100
101 1
        foreach ($tokens as $token) {
102 1
            if (0 === strpos($this->getTokenizedQuery(), $matchSoFar.$token['str'])) {
103 1
                $matchSoFar .= $token['str'];
104 1
                $matchDataSoFar[] = [
105 1
                    'id' => $token['o_rev_id'],
106 1
                    'editor' => $token['editor'],
107 1
                    'token' => $token['str'],
108
                ];
109 1
            } elseif (!empty($matchSoFar)) {
110
                $matchDataSoFar = [];
111
                $matchSoFar = '';
112
            }
113
114 1
            if ($matchSoFar === $this->getTokenizedQuery()) {
115 1
                $matchData = array_merge($matchData, $matchDataSoFar);
116 1
                $matchDataSoFar = [];
117 1
                $matchSoFar = '';
118
            }
119
        }
120
121
        // Full matches usually come last, but are the most relevant.
122 1
        return array_reverse($matchData);
123
    }
124
}
125