1<?php
2/**
3 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
4 * @author     <dae@douglasedmunds.com>
5 * @author     Andy Webber <dokuwiki at andywebber dot com>
6 * @author     Federico Ariel Castagnini
7 * @author     Cyrille37 <cyrille37@gmail.com>
8 * @author     Matthias Schulte <dokuwiki@lupo49.de>
9 * @author     Rik Blok <rik dot blok at ubc dot ca>
10 * @author     Christian Paul <christian at chrpaul dot de>
11 * @author     alexdraconian
12 */
13// must be run within Dokuwiki
14if(!defined('DOKU_INC')) die();
15if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
16
17require_once(DOKU_INC.'inc/search.php');
18
19class helper_plugin_orphanswanted extends DokuWiki_Plugin {
20
21    //    three choices
22    //    $params_array used to extract excluded namespaces for report
23    //    orphans =  orph_report_table($data, true, false, $params_array);
24    //    wanted =  orph_report_table($data, false, true), $params_array;
25    //    valid  =  orph_report_table($data, true, true, $params_array);
26
27    /**
28     * Find all page list with wiki's internal indexer.
29     */
30    function _get_page_data() {
31        $all_pages = idx_get_indexer()->getPages();
32        $pages = array();
33        foreach($all_pages as $pageid) {
34            $pages[$pageid] = array("exists"=>page_exists($pageid), "links"=>0);
35        }
36
37        foreach($all_pages as $pageid) {
38
39            if (!page_exists($pageid)) continue;
40
41            $relation_data = p_get_metadata($pageid, 'relation references', METADATA_DONT_RENDER);
42            if (!is_null($relation_data)) {
43                foreach($relation_data as $name => $exists) {
44                    $pages[$name]['exists'] = $exists;
45                    $pages[$name]['links'] = isset($pages[$name]['links']) ? $pages[$name]['links'] + 1 : 1;
46                }
47            }
48        }
49
50        return $pages;
51    }
52
53    function orphan_pages($params_array) {
54        $data = $this->_get_page_data();
55
56        $result = '';
57        $result .=  $this->orph_report_table($data, true, false, $params_array, 'orphan');
58
59        return $result;
60    }
61
62    function wanted_pages($params_array) {
63        $data = $this->_get_page_data();
64
65        $result = '';
66        $result .=  $this->orph_report_table($data, false, true, $params_array, 'wanted');
67
68        return $result;
69    }
70
71    function valid_pages($params_array) {
72        $data = $this->_get_page_data();
73
74        $result = '';
75        $result .=  $this->orph_report_table($data, true, true, $params_array, 'valid');
76
77        return $result;
78    }
79
80    function all_pages($params_array) {
81        $data = $this->_get_page_data();
82
83        $result = '';
84        $result .= "</p><p>Orphans</p><p>";
85        $result .= $this->orph_report_table($data, true, false, $params_array, 'orphan');
86        $result .= "</p><p>Wanted</p><p>";
87        $result .= $this->orph_report_table($data, false, true, $params_array, 'wanted');
88        $result .= "</p><p>Valid</p><p>";
89        $result .= $this->orph_report_table($data, true, true, $params_array, 'valid');
90
91        return $result;
92    }
93
94    function orph_report_table($data, $page_exists, $has_links, $params_array, $caller = null) {
95        global $conf;
96        $ignoredPages = $this->getConf('ignoredpages'); // Fetch pages which shouldn't be listed
97        if($ignoredPages != '') {
98            $ignoredPages = explode(';', $ignoredPages);
99        } else {
100            $ignoredPages = null;
101        }
102
103        $show_heading = ($page_exists && $conf['useheading']) ? true : false ;
104        //take off $params_array[0];
105        $include_array = $params_array[1];
106        $exclude_array = $params_array[2];
107
108        $count = 1;
109        $output = '';
110
111        // for valid html - need to close the <p> that is feed before this
112        $output .= '</p>';
113        $output .= '<table class="inline"><tr><th> # </th><th> ID </th>'
114                    . ($show_heading ? '<th>Title</th>' : '' )
115                    . ($caller != "orphan" ? '<th>Links</th>' : '')
116                    . '</tr>'
117                    . "\n" ;
118
119        // Sort by namespace and name
120        ksort($data);
121
122        // Sort descending by existing links.
123        // This does not make sense for orphans since they don't have links.
124        if ($caller != "orphan") {
125            arsort($data);
126        }
127
128        foreach($data as $id=>$item) {
129
130            if( ! ((array_key_exists('exists', $item)) and ($item['exists'] == $page_exists) and (array_key_exists('links', $item)) and (($item['links'] <> 0)== $has_links)) ) continue ;
131
132            // $id is a string, looks like this: page, namespace:page, or namespace:<subspaces>:page
133            $match_array = explode(":", $id);
134            //remove last item in array, the page identifier
135            $match_array = array_slice($match_array, 0, -1);
136            //put it back together
137            $page_namespace = implode (":", $match_array);
138            //add a trailing :
139            $page_namespace = $page_namespace . ':';
140
141            if (empty($include_array)) {
142                // if inclusion list is empty then show all namespaces
143                $show_it = true;
144            } else {
145                // otherwise only show if in inclusion list
146                $show_it = false;
147                foreach ($include_array as $include_item) {
148                    //add a trailing : to each $item too
149                    $include_item = $include_item . ":";
150                    // need === to avoid boolean false
151                    // strpos(haystack, needle)
152                    // if exclusion is beginning of page's namespace, block it
153                    if (strpos($page_namespace, $include_item) === 0) {
154                        //there is a match, so show it and move on
155                        $show_it = true;
156                        break;
157                    }
158                }
159            }
160
161            if(!is_null($ignoredPages) && in_array($id, $ignoredPages)) {
162                if ($conf['allowdebug']) echo "Skipped page (global ignored): " . $id . "<br />";
163                $show_it = false;
164            } elseif(isHiddenPage($id)) {
165                if ($conf['allowdebug']) echo "Skipped page (global hidden): " . $id . "<br />";
166                $show_it = false;
167            } elseif ( $show_it )  {
168                //check if blocked by exclusion list
169                foreach ($exclude_array as $exclude_item) {
170                    //add a trailing : to each $item too
171                    $exclude_item = $exclude_item . ":";
172                    // need === to avoid boolean false
173                    // strpos(haystack, needle)
174                    // if exclusion is beginning of page's namespace , block it
175                    if (strpos($page_namespace, $exclude_item) === 0) {
176                        //there is a match, so block it and move on
177                        $show_it = false;
178                        break;
179                    }
180                }
181            }
182
183            if($show_it) {
184                $output .=  "<tr><td>$count</td><td><a href=\"". wl($id)
185                            . "\" class=\"" . ($page_exists ? "wikilink1" : "wikilink2") . "\" >"
186                            . $id .'</a></td>'
187                            . ($show_heading ? '<td>' . hsc(p_get_first_heading($id)) .'</td>' : '' );
188
189                if($caller != "orphan") { // Skip "link" column if user wants orphan pages only
190                    $output .= '<td>' . $item['links']
191                                . ($has_links ? "&nbsp;:&nbsp;<a href=\"". wl($id, 'do=backlink')
192                                . "\" class=\"wikilink1\">Show&nbsp;backlinks</a>" : '') . "</td>";
193                }
194                $output .= "</tr>\n";
195                $count++;
196            }
197        }
198
199        $output .=  "</table>\n";
200        //for valid html = need to reopen a <p>
201        $output .= '<p>';
202
203        return $output;
204    }
205}
206