xref: /dokuwiki/inc/TreeBuilder/TreeSort.php (revision 1b8e843ae8a101ec62b750d9d4b97463bb344d9f)
1<?php
2
3namespace dokuwiki\TreeBuilder;
4
5use dokuwiki\TreeBuilder\Node\AbstractNode;
6use dokuwiki\TreeBuilder\Node\WikiNamespace;
7use dokuwiki\Utf8\Sort;
8
9/**
10 * Class that provides comparators for sorting the tree nodes
11 */
12class TreeSort
13{
14    public const SORT_BY_ID = [self::class, 'sortById'];
15    public const SORT_BY_TITLE = [self::class, 'sortByTitle'];
16    public const SORT_BY_NS_FIRST_THEN_ID = [self::class, 'sortByNsFirstThenId'];
17    public const SORT_BY_NS_FIRST_THEN_TITLE = [self::class, 'sortByNsFirstThenTitle'];
18
19    /**
20     * Comparator to sort by ID
21     *
22     * @param AbstractNode $a
23     * @param AbstractNode $b
24     * @return int
25     */
26    public static function sortById(AbstractNode $a, AbstractNode $b): int
27    {
28        // we need to compare the ID segment by segment
29        $pathA = explode(':', $a->getId());
30        $pathB = explode(':', $b->getId());
31        $min = min(count($pathA), count($pathB));
32
33        for ($i = 0; $i < $min; $i++) {
34            if ($pathA[$i] !== $pathB[$i]) {
35                return $pathA[$i] <=> $pathB[$i];
36            }
37        }
38        return count($pathA) <=> count($pathB);
39    }
40
41
42    /**
43     * Comparator to sort namespace first, then by ID
44     *
45     * @param AbstractNode $a
46     * @param AbstractNode $b
47     * @return int
48     */
49    public static function sortByNsFirstThenId(AbstractNode $a, AbstractNode $b): int
50    {
51        $res = self::sortByNsFirst($a, $b);
52        if ($res === 0) $res = self::sortById($a, $b);
53        return $res;
54    }
55
56    /**
57     * Comparator to sort by title (using natural sort)
58     *
59     * @param AbstractNode $a
60     * @param AbstractNode $b
61     * @return int
62     */
63    public static function sortByTitle(AbstractNode $a, AbstractNode $b): int
64    {
65        return Sort::strcmp($a->getTitle(), $b->getTitle());
66    }
67
68    /**
69     * Comparator to sort namespace first, then by title
70     *
71     * @param AbstractNode $a
72     * @param AbstractNode $b
73     * @return int
74     */
75    public static function sortByNsFirstThenTitle(AbstractNode $a, AbstractNode $b): int
76    {
77        $res = self::sortByNsFirst($a, $b);
78        if ($res === 0) $res = self::sortByTitle($a, $b);
79        return $res;
80    }
81
82    /**
83     * Comparator to sort by namespace first
84     *
85     * @param AbstractNode $a
86     * @param AbstractNode $b
87     * @return int
88     */
89    protected static function sortByNsFirst(AbstractNode $a, AbstractNode $b): int
90    {
91        $isAaNs = ($a instanceof WikiNamespace);
92        $isBaNs = ($b instanceof WikiNamespace);
93
94        if ($isAaNs !== $isBaNs) {
95            if ($isAaNs) {
96                return -1;
97            } elseif ($isBaNs) {
98                return 1;
99            }
100        }
101        return 0;
102    }
103}
104