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