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