Completed
Push — svgpagetools ( bbaba7...d7814e )
by Andreas
10:59 queued 07:19
created

bin/wantedpages.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
#!/usr/bin/php
2
<?php
3
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
4
define('NOSESSION', 1);
5
require_once(DOKU_INC . 'inc/init.php');
6
7
/**
8
 * Find wanted pages
9
 */
10
class WantedPagesCLI extends DokuCLI {
11
12
    const DIR_CONTINUE = 1;
13
    const DIR_NS = 2;
14
    const DIR_PAGE = 3;
15
16
    private $skip = false;
17
    private $sort = 'wanted';
18
19
    private $result = array();
20
21
    /**
22
     * Register options and arguments on the given $options object
23
     *
24
     * @param DokuCLI_Options $options
25
     * @return void
26
     */
27
    protected function setup(DokuCLI_Options $options) {
28
        $options->setHelp(
29
            'Outputs a list of wanted pages (pages that do not exist yet) and their origin pages ' .
30
            ' (the pages that are linkin to these missing pages).'
31
        );
32
        $options->registerArgument(
33
            'namespace',
34
            'The namespace to lookup. Defaults to root namespace',
35
            false
36
        );
37
38
        $options->registerOption(
39
            'sort',
40
            'Sort by wanted or origin page',
41
            's',
42
            '(wanted|origin)'
43
        );
44
45
        $options->registerOption(
46
            'skip',
47
            'Do not show the second dimension',
48
            'k'
49
        );
50
    }
51
52
    /**
53
     * Your main program
54
     *
55
     * Arguments and options have been parsed when this is run
56
     *
57
     * @param DokuCLI_Options $options
58
     * @return void
59
     */
60
    protected function main(DokuCLI_Options $options) {
61
62
        if($options->args) {
63
            $startdir = dirname(wikiFN($options->args[0] . ':xxx'));
64
        } else {
65
            $startdir = dirname(wikiFN('xxx'));
66
        }
67
68
        $this->skip = $options->getOpt('skip');
0 ignored issues
show
Documentation Bug introduced by
It seems like $options->getOpt('skip') can also be of type string. However, the property $skip is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
69
        $this->sort = $options->getOpt('sort');
0 ignored issues
show
Documentation Bug introduced by
It seems like $options->getOpt('sort') can also be of type boolean. However, the property $sort is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
70
71
        $this->info("searching $startdir");
72
73
        foreach($this->get_pages($startdir) as $page) {
74
            $this->internal_links($page);
75
        }
76
        ksort($this->result);
77
        foreach($this->result as $main => $subs) {
78
            if($this->skip) {
79
                print "$main\n";
80
            } else {
81
                $subs = array_unique($subs);
82
                sort($subs);
83
                foreach($subs as $sub) {
84
                    printf("%-40s %s\n", $main, $sub);
85
                }
86
            }
87
        }
88
    }
89
90
    /**
91
     * Determine directions of the search loop
92
     *
93
     * @param string $entry
94
     * @param string $basepath
95
     * @return int
96
     */
97
    protected function dir_filter($entry, $basepath) {
98
        if($entry == '.' || $entry == '..') {
99
            return WantedPagesCLI::DIR_CONTINUE;
100
        }
101
        if(is_dir($basepath . '/' . $entry)) {
102
            if(strpos($entry, '_') === 0) {
103
                return WantedPagesCLI::DIR_CONTINUE;
104
            }
105
            return WantedPagesCLI::DIR_NS;
106
        }
107
        if(preg_match('/\.txt$/', $entry)) {
108
            return WantedPagesCLI::DIR_PAGE;
109
        }
110
        return WantedPagesCLI::DIR_CONTINUE;
111
    }
112
113
    /**
114
     * Collects recursively the pages in a namespace
115
     *
116
     * @param string $dir
117
     * @return array
118
     * @throws DokuCLI_Exception
119
     */
120
    protected function get_pages($dir) {
121
        static $trunclen = null;
122
        if(!$trunclen) {
123
            global $conf;
124
            $trunclen = strlen($conf['datadir'] . ':');
125
        }
126
127
        if(!is_dir($dir)) {
128
            throw new DokuCLI_Exception("Unable to read directory $dir");
129
        }
130
131
        $pages = array();
132
        $dh = opendir($dir);
133
        while(false !== ($entry = readdir($dh))) {
134
            $status = $this->dir_filter($entry, $dir);
135
            if($status == WantedPagesCLI::DIR_CONTINUE) {
136
                continue;
137
            } else if($status == WantedPagesCLI::DIR_NS) {
138
                $pages = array_merge($pages, $this->get_pages($dir . '/' . $entry));
139
            } else {
140
                $page = array(
141
                    'id' => pathID(substr($dir . '/' . $entry, $trunclen)),
142
                    'file' => $dir . '/' . $entry,
143
                );
144
                $pages[] = $page;
145
            }
146
        }
147
        closedir($dh);
148
        return $pages;
149
    }
150
151
    /**
152
     * Parse instructions and add the non-existing links to the result array
153
     *
154
     * @param array $page array with page id and file path
155
     */
156
    function internal_links($page) {
157
        global $conf;
158
        $instructions = p_get_instructions(file_get_contents($page['file']));
159
        $cns = getNS($page['id']);
160
        $exists = false;
161
        $pid = $page['id'];
162
        foreach($instructions as $ins) {
163
            if($ins[0] == 'internallink' || ($conf['camelcase'] && $ins[0] == 'camelcaselink')) {
164
                $mid = $ins[1][0];
165
                resolve_pageid($cns, $mid, $exists);
166
                if(!$exists) {
167
                    list($mid) = explode('#', $mid); //record pages without hashes
168
169
                    if($this->sort == 'origin') {
170
                        $this->result[$pid][] = $mid;
171
                    } else {
172
                        $this->result[$mid][] = $pid;
173
                    }
174
                }
175
            }
176
        }
177
    }
178
}
179
180
// Main
181
$cli = new WantedPagesCLI();
182
$cli->run();
183