Failed Conditions
Push — master ( b2c9cd...43d3f0 )
by Andreas
12:59 queued 09:00
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
4
use splitbrain\phpcli\CLI;
5
use splitbrain\phpcli\Options;
6
7
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
8
define('NOSESSION', 1);
9
require_once(DOKU_INC . 'inc/init.php');
10
11
/**
12
 * Find wanted pages
13
 */
14
class WantedPagesCLI extends CLI {
15
16
    const DIR_CONTINUE = 1;
17
    const DIR_NS = 2;
18
    const DIR_PAGE = 3;
19
20
    private $skip = false;
21
    private $sort = 'wanted';
22
23
    private $result = array();
24
25
    /**
26
     * Register options and arguments on the given $options object
27
     *
28
     * @param Options $options
29
     * @return void
30
     */
31
    protected function setup(Options $options) {
32
        $options->setHelp(
33
            'Outputs a list of wanted pages (pages that do not exist yet) and their origin pages ' .
34
            ' (the pages that are linkin to these missing pages).'
35
        );
36
        $options->registerArgument(
37
            'namespace',
38
            'The namespace to lookup. Defaults to root namespace',
39
            false
40
        );
41
42
        $options->registerOption(
43
            'sort',
44
            'Sort by wanted or origin page',
45
            's',
46
            '(wanted|origin)'
47
        );
48
49
        $options->registerOption(
50
            'skip',
51
            'Do not show the second dimension',
52
            'k'
53
        );
54
    }
55
56
    /**
57
     * Your main program
58
     *
59
     * Arguments and options have been parsed when this is run
60
     *
61
     * @param Options $options
62
     * @return void
63
     */
64
    protected function main(Options $options) {
65
        $args = $options->getArgs();
66
        if($args) {
67
            $startdir = dirname(wikiFN($args[0] . ':xxx'));
68
        } else {
69
            $startdir = dirname(wikiFN('xxx'));
70
        }
71
72
        $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 or array<integer,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...
73
        $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 or array<integer,string>. 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...
74
75
        $this->info("searching $startdir");
76
77
        foreach($this->get_pages($startdir) as $page) {
78
            $this->internal_links($page);
79
        }
80
        ksort($this->result);
81
        foreach($this->result as $main => $subs) {
82
            if($this->skip) {
83
                print "$main\n";
84
            } else {
85
                $subs = array_unique($subs);
86
                sort($subs);
87
                foreach($subs as $sub) {
88
                    printf("%-40s %s\n", $main, $sub);
89
                }
90
            }
91
        }
92
    }
93
94
    /**
95
     * Determine directions of the search loop
96
     *
97
     * @param string $entry
98
     * @param string $basepath
99
     * @return int
100
     */
101
    protected function dir_filter($entry, $basepath) {
102
        if($entry == '.' || $entry == '..') {
103
            return WantedPagesCLI::DIR_CONTINUE;
104
        }
105
        if(is_dir($basepath . '/' . $entry)) {
106
            if(strpos($entry, '_') === 0) {
107
                return WantedPagesCLI::DIR_CONTINUE;
108
            }
109
            return WantedPagesCLI::DIR_NS;
110
        }
111
        if(preg_match('/\.txt$/', $entry)) {
112
            return WantedPagesCLI::DIR_PAGE;
113
        }
114
        return WantedPagesCLI::DIR_CONTINUE;
115
    }
116
117
    /**
118
     * Collects recursively the pages in a namespace
119
     *
120
     * @param string $dir
121
     * @return array
122
     * @throws DokuCLI_Exception
123
     */
124
    protected function get_pages($dir) {
125
        static $trunclen = null;
126
        if(!$trunclen) {
127
            global $conf;
128
            $trunclen = strlen($conf['datadir'] . ':');
129
        }
130
131
        if(!is_dir($dir)) {
132
            throw new DokuCLI_Exception("Unable to read directory $dir");
133
        }
134
135
        $pages = array();
136
        $dh = opendir($dir);
137
        while(false !== ($entry = readdir($dh))) {
138
            $status = $this->dir_filter($entry, $dir);
139
            if($status == WantedPagesCLI::DIR_CONTINUE) {
140
                continue;
141
            } else if($status == WantedPagesCLI::DIR_NS) {
142
                $pages = array_merge($pages, $this->get_pages($dir . '/' . $entry));
143
            } else {
144
                $page = array(
145
                    'id' => pathID(substr($dir . '/' . $entry, $trunclen)),
146
                    'file' => $dir . '/' . $entry,
147
                );
148
                $pages[] = $page;
149
            }
150
        }
151
        closedir($dh);
152
        return $pages;
153
    }
154
155
    /**
156
     * Parse instructions and add the non-existing links to the result array
157
     *
158
     * @param array $page array with page id and file path
159
     */
160
    function internal_links($page) {
161
        global $conf;
162
        $instructions = p_get_instructions(file_get_contents($page['file']));
163
        $cns = getNS($page['id']);
164
        $exists = false;
165
        $pid = $page['id'];
166
        foreach($instructions as $ins) {
167
            if($ins[0] == 'internallink' || ($conf['camelcase'] && $ins[0] == 'camelcaselink')) {
168
                $mid = $ins[1][0];
169
                resolve_pageid($cns, $mid, $exists);
170
                if(!$exists) {
171
                    list($mid) = explode('#', $mid); //record pages without hashes
172
173
                    if($this->sort == 'origin') {
174
                        $this->result[$pid][] = $mid;
175
                    } else {
176
                        $this->result[$mid][] = $pid;
177
                    }
178
                }
179
            }
180
        }
181
    }
182
}
183
184
// Main
185
$cli = new WantedPagesCLI();
186
$cli->run();
187