summaryrefslogtreecommitdiffstats
path: root/modules/doc/library/Doc/Search/DocSearchIterator.php
blob: fd2c90300adf4dd3888a28a009a8a7aaeba5a70b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<?php
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */

namespace Icinga\Module\Doc\Search;

use RecursiveFilterIterator;
use RecursiveIteratorIterator;
use Icinga\Data\Tree\TreeNodeIterator;

/**
 * Iterator over doc sections that match a given search criteria
 */
class DocSearchIterator extends RecursiveFilterIterator
{
    /**
     * Search criteria
     *
     * @var DocSearch
     */
    protected $search;

    /**
     * Current search matches
     *
     * @var DocSearchMatch[]|null
     */
    protected $matches;

    /**
     * Create a new iterator over doc sections that match the given search criteria
     *
     * @param TreeNodeIterator  $iterator
     * @param DocSearch         $search
     */
    public function __construct(TreeNodeIterator $iterator, DocSearch $search)
    {
        $this->search = $search;
        parent::__construct($iterator);
    }

    /**
     * Accept sections that match the search
     *
     * @return bool Whether the current element of the iterator is acceptable
     *              through this filter
     */
    public function accept(): bool
    {
        $section = $this->current();
        /** @var $section \Icinga\Module\Doc\DocSection */
        $matches = array();
        if (($match = $this->search->search($section->getTitle())) !== null) {
            $matches[] = $match->setMatchType(DocSearchMatch::MATCH_HEADER);
        }
        foreach ($section->getContent() as $lineno => $line) {
            if (($match = $this->search->search($line)) !== null) {
                $matches[] = $match
                    ->setMatchType(DocSearchMatch::MATCH_CONTENT)
                    ->setLineno($lineno);
            }
        }
        if (! empty($matches)) {
            $this->matches = $matches;
            return true;
        }
        if ($section->hasChildren()) {
            $this->matches = null;
            return true;
        }
        return false;
    }

    /**
     * Get the search criteria
     *
     * @return DocSearch
     */
    public function getSearch()
    {
        return $this->search;
    }

    public function getChildren(): self
    {
        return new static($this->getInnerIterator()->getChildren(), $this->search);
    }

    /**
     * Whether the search did not yield any match
     *
     * @return bool
     */
    public function isEmpty()
    {
        $iter = new RecursiveIteratorIterator($this, RecursiveIteratorIterator::SELF_FIRST);
        foreach ($iter as $section) {
            if ($iter->getInnerIterator()->getMatches() !== null) {
                return false;
            }
        }
        return true;
    }

    /**
     * Get current matches
     *
     * @return DocSearchMatch[]|null
     */
    public function getMatches()
    {
        return $this->matches;
    }
}