1<?php
2
3namespace ComboStrap\Tag;
4
5use ComboStrap\ExceptionCompile;
6use ComboStrap\LinkMarkup;
7use ComboStrap\LogUtility;
8use ComboStrap\MarkupPath;
9use ComboStrap\PluginUtility;
10use ComboStrap\SiteConfig;
11use ComboStrap\TagAttributes;
12use syntax_plugin_combo_iterator;
13use syntax_plugin_combo_related;
14
15class RelatedTag
16{
17
18
19    public const TAG = "related";
20    /**
21     * For when you come from another plugin (such as backlinks) and that you don't want to change the pattern on each page
22     */
23    public const MORE_PAGE_ID = 'related_more';
24    public const MAX_LINKS_CONF = 'maxLinks';
25    public const EXTRA_PATTERN_CONF = 'extra_pattern';
26    public const MAX_LINKS_CONF_DEFAULT = 10;
27    /**
28     * The array key of an array of related page
29     */
30    public const RELATED_BACKLINKS_COUNT_PROP = 'backlinks';
31    /**
32     * This is a fake page ID that is added
33     * to the related page array when the number of backlinks is bigger than the max
34     */
35    public const RELATED_PAGE_ID_PROP = 'id';
36
37    /**
38     * @param TagAttributes $tagAttributes
39     * @param MarkupPath $page
40     * @param int|null $max
41     * @return string
42     */
43    public static function render(TagAttributes $tagAttributes): string
44    {
45        $path = syntax_plugin_combo_iterator::getContextPathForComponentThatMayBeInFragment($tagAttributes);
46        $contextPage = MarkupPath::createPageFromPathObject($path);
47        return self::renderForPage($contextPage, $tagAttributes);
48    }
49
50    public static function renderForPage(MarkupPath $page, TagAttributes $tagAttributes = null): string
51    {
52        global $lang;
53
54        if ($tagAttributes === null) {
55            $tagAttributes = TagAttributes::createEmpty()
56                ->setLogicalTag(self::TAG);
57        }
58
59        $max = $tagAttributes->getValue(RelatedTag::MAX_LINKS_CONF);
60        if ($max === NULL) {
61            $max = SiteConfig::getConfValue(RelatedTag::MAX_LINKS_CONF, RelatedTag::MAX_LINKS_CONF_DEFAULT);
62        }
63
64        $tagAttributes->addClassName("d-print-none");
65        $html = $tagAttributes->toHtmlEnterTag("div");
66
67        $relatedPages = self::getRelatedPagesOrderedByBacklinkCount($page, $max);
68        if (empty($relatedPages)) {
69
70            $html .= "<strong>Plugin " . PluginUtility::PLUGIN_BASE_NAME . " - Component " . syntax_plugin_combo_related::getTag() . ": " . $lang['nothingfound'] . "</strong>";
71
72        } else {
73
74            // Dokuwiki debug
75
76            $html .= '<ul>';
77
78            foreach ($relatedPages as $backlink) {
79                $backlinkId = $backlink[self::RELATED_PAGE_ID_PROP];
80                $html .= '<li>';
81                if ($backlinkId != self::MORE_PAGE_ID) {
82                    $linkUtility = LinkMarkup::createFromPageIdOrPath($backlinkId);
83                    try {
84                        $html .= $linkUtility->toAttributes(self::TAG)->toHtmlEnterTag("a");
85                        $html .= $linkUtility->getDefaultLabel();
86                        $html .= "</a>";
87                    } catch (ExceptionCompile $e) {
88                        $html = "Error while trying to create the link for the page ($backlinkId). Error: {$e->getMessage()}";
89                        LogUtility::msg($html);
90                    }
91
92                } else {
93                    $html .=
94                        tpl_link(
95                            wl($page->getWikiId()) . '?do=backlink',
96                            "More ...",
97                            'class="" rel="nofollow" title="More..."',
98                            true
99                        );
100                }
101                $html .= '</li>';
102            }
103
104            $html .= '</ul>';
105
106        }
107
108        return $html . '</div>';
109    }
110
111    /**
112     * @param MarkupPath $page
113     * @param int|null $max
114     * @return array
115     */
116    public static function getRelatedPagesOrderedByBacklinkCount(MarkupPath $page, ?int $max = null): array
117    {
118
119        // Call the dokuwiki backlinks function
120        // @require_once(DOKU_INC . 'inc/fulltext.php');
121        // Backlinks called the indexer, for more info
122        // See: https://www.dokuwiki.org/devel:metadata#metadata_index
123        $backlinks = ft_backlinks($page->getWikiId(), $ignore_perms = false);
124
125        $related = array();
126        foreach ($backlinks as $backlink) {
127            $page = array();
128            $page[RelatedTag::RELATED_PAGE_ID_PROP] = $backlink;
129            $page[RelatedTag::RELATED_BACKLINKS_COUNT_PROP] = sizeof(ft_backlinks($backlink, $ignore_perms = false));
130            $related[] = $page;
131        }
132
133        usort($related, function ($a, $b) {
134            return $b[RelatedTag::RELATED_BACKLINKS_COUNT_PROP] - $a[RelatedTag::RELATED_BACKLINKS_COUNT_PROP];
135        });
136
137        if ($max !== null) {
138            if (sizeof($related) > $max) {
139                $related = array_slice($related, 0, $max);
140                $page = array();
141                $page[RelatedTag::RELATED_PAGE_ID_PROP] = RelatedTag::MORE_PAGE_ID;
142                $related[] = $page;
143            }
144        }
145
146        return $related;
147
148    }
149}
150