1<?php
2/**
3 * Plugin nspages : Displays nicely a list of the pages of a namespace
4 *
5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 */
7if(!defined('DOKU_INC')) die();
8require_once 'filePreparer.php';
9
10class pagePreparer extends filePreparer {
11
12    private $customTitle;
13    private $customTitleAllowListMetadata;
14    private $sortByMetadata;
15
16    function __construct($excludedNs, $excludedFiles, $pregOn, $pregOff, $pregTitleOn, $pregTitleOff, $useTitle,
17                         $sortPageById, $useIdAndTitle, $sortPageByDate, $sortByCreationDate, $customTitle,
18                         $customTitleAllowListMetadata, $sortByMetadata) {
19        parent::__construct($excludedFiles, $pregOn, $pregOff, $pregTitleOn, $pregTitleOff, $useTitle, $sortPageById,
20            $useIdAndTitle, $sortPageByDate, $sortByCreationDate);
21
22        $this->excludedNs = $excludedNs;
23        $this->customTitle = $customTitle;
24        $this->customTitleAllowListMetadata = $customTitleAllowListMetadata;
25        $this->sortByMetadata = $sortByMetadata;
26    }
27
28    function isFileWanted($file, $useTitle){
29        return ($file['type'] != 'd') && parent::isFileWanted($file, $useTitle) && $this->passSubNsfilterInRecursiveMode($file);
30    }
31
32    function prepareFileTitle(&$file){
33        // Nothing to do: for pages the title is already set
34    }
35
36    private function passSubNsfilterInRecursiveMode($file){
37        $subNss = explode(':', $file['id']);
38        if ( count($subNss) < 2 ){ //It means we're not in recursive mode
39            return true;
40        }
41        for ($i = 0; $i < count($subNss) - 1; $i++) {
42            if (in_array($subNss[$i], $this->excludedNs)) {
43                return false;
44            }
45        }
46        return true;
47    }
48
49    function prepareFile(&$page){
50        $page['nameToDisplay'] = $this->buildNameToDisplay($page);
51        $page['sort'] = $this->buildSortAttribute($page['nameToDisplay'], $page['id'], $page['mtime']);
52    }
53
54    /**
55     * Get the a metadata value from a certain path.
56     *
57     * @param $metadata - The metadata object of a page. More details on https://www.dokuwiki.org/devel:metadata
58     * @param $path - The path.
59     *  Examples:
60     *      date.created
61     *      contributor.0
62     *
63     * @return mixed - The metadata value from a certain path.
64     */
65
66    private function getMetadataFromPath($metadata, $path) {
67        return array_reduce(
68            explode('.', $path),
69            function ($object, $property) {
70                return is_numeric($property) ? $object[$property] : $object[$property];
71            },
72            $metadata
73        );
74    }
75
76    private function isPathInMetadataAllowList($path) {
77        $metadataAllowList = explode(',', preg_replace('/\s+/', '', $this->customTitleAllowListMetadata));
78        return in_array($path, $metadataAllowList);
79    }
80
81    /**
82     * Get the page custom title from a template.
83     *
84     * @param $customTitle - The custom tile template.
85     *  Examples:
86     *      {title} ({data.created} by {user})
87     * @param $metadata - The metadata object of a page. More details on https://www.dokuwiki.org/devel:metadata
88     *
89     * @return string - the custom title
90     */
91
92    private function getCustomTitleFromTemplate($customTitle, $metadata) {
93        return preg_replace_callback(
94            '/{(.*?)}/',
95            function ($matches) use($metadata) {
96                $path = $matches[1];
97                if ($this->isPathInMetadataAllowList($path)) {
98                    return $this->getMetadataFromPath($metadata, $path);
99                } else {
100                    return $path;
101                }
102            },
103            $customTitle
104        );
105    }
106
107    private function buildNameToDisplay($page){
108        $title = $page['title'];
109        $pageId = $page['id'];
110
111
112        if ($this->customTitle !== null) {
113            $meta = p_get_metadata($pageId);
114            return $this->getCustomTitleFromTemplate($this->customTitle, $meta);
115        }
116
117        if($this->useIdAndTitle && $title !== null ){
118          return noNS($pageId) . " - " . $title;
119        }
120
121        if(!$this->useTitle || $title === null) {
122            return noNS($pageId);
123        }
124        return $title;
125    }
126
127    private function buildSortAttribute($nameToDisplay, $pageId, $mtime){
128        if ($this->sortByMetadata !== null) {
129            $meta = p_get_metadata($pageId);
130            return $this->getMetadataFromPath($meta, $this->sortByMetadata);
131        } else if($this->sortPageById) {
132            return noNS($pageId);
133        } else if ( $this->sortPageByDate) {
134            return $mtime;
135        } else if ($this->sortByCreationDate) {
136            $meta = p_get_metadata($pageId);
137            return $meta['date']['created'];
138        } else {
139            return $nameToDisplay;
140        }
141
142    }
143}
144