Passed
Push — master ( 942d5f...e1495e )
by Andreas
18:45
created

parser::walk_variables()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 9.3088

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 12
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 22
ccs 4
cts 13
cp 0.3076
crap 9.3088
rs 9.8666
1
<?php
2
/**
3
 * @package midcom.routing
4
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
namespace midcom\routing;
10
11
use midcom_connection;
12
use midcom_core_context;
13
use midcom_db_topic;
14
15
/**
16
 * URL name parser that uses the topic structure
17
 *
18
 * @package midcom.routing
19
 */
20
class parser
21
{
22
    public $argv = [];
23
24
    /**
25
     * @var midcom_db_topic
26
     */
27
    private $current;
28
29
    private $url = '';
30
31
    /**
32
     * Objects by URL
33
     *
34
     * @var midcom_db_topic[]
35
     */
36
    private $objects = [];
37
38
    /**
39
     * @var midcom_core_context
40
     */
41
    private $context;
42
43 339
    public function __construct(midcom_core_context $context)
44
    {
45 339
        $this->context = $context;
46 339
        $url = $this->context->get_key(MIDCOM_CONTEXT_URI);
47
48 339
        $prefix_length = strlen(midcom_connection::get_url('prefix'));
49 339
        if (   $prefix_length > 1
50 339
            && substr($url, 0, $prefix_length) == midcom_connection::get_url('prefix')) {
0 ignored issues
show
Bug introduced by
It seems like $url can also be of type false; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

50
            && substr(/** @scrutinizer ignore-type */ $url, 0, $prefix_length) == midcom_connection::get_url('prefix')) {
Loading history...
51
            $url = substr($url, $prefix_length);
52
        }
53 339
        $url = trim($url, '/');
54 339
        if ($url != '') {
55 323
            $argv = explode('/', $url);
56 323
            foreach ($argv as $val) {
57 323
                if ($val !== '') {
58 323
                    $this->argv[] = $val;
59
                }
60
            }
61
        }
62 339
    }
63
64
    /**
65
     * Try to fetch a URL variable.
66
     *
67
     * Try to decode an midcom-<key>-<value> pair at the current URL
68
     * position.
69
     *
70
     * On success it returns the command it found.
71
     *
72
     * @return string|boolean
73
     */
74 338
    public function find_urlmethod() : ?string
75
    {
76 338
        if (   empty($this->argv)
77 338
            || strpos($this->argv[0], 'midcom-') !== 0) {
78 338
            return null;
79
        }
80
        return '/' . implode('/', $this->argv);
81
    }
82
83
    /**
84
     * @throws \midcom_error
85
     */
86 338
    public function find_topic() : midcom_db_topic
87
    {
88 338
        $this->current = $this->context->get_key(MIDCOM_CONTEXT_ROOTTOPIC);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->context->get_key(...DCOM_CONTEXT_ROOTTOPIC) can also be of type false. However, the property $current is declared as type midcom_db_topic. 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...
89 338
        if (!$this->current) {
90
            throw new \midcom_error('Root node missing.');
91
        }
92 338
        $this->walk_topics();
93
94
        // Initialize context
95 338
        $this->context->set_key(MIDCOM_CONTEXT_ANCHORPREFIX, midcom_connection::get_url('self') . $this->url);
96 338
        $this->context->set_key(MIDCOM_CONTEXT_COMPONENT, $this->current->component);
97 338
        $this->context->set_key(MIDCOM_CONTEXT_CONTENTTOPIC, $this->current);
98 338
        $this->context->set_key(MIDCOM_CONTEXT_URLTOPICS, $this->objects);
99
100 338
        return $this->current;
101
    }
102
103
    /**
104
     * Load topics recursively from argv
105
     */
106 338
    private function walk_topics()
107
    {
108 338
        if (empty($this->argv)) {
109
            // No arguments left
110 20
            return;
111
        }
112
113 322
        $object_url = $this->argv[0] . '/';
114 322
        if (!empty($this->url)) {
115 3
            $object_url = $this->url . $object_url;
116
        }
117 322
        if (!array_key_exists($object_url, $this->objects)) {
118 322
            $qb = midcom_db_topic::new_query_builder();
119 322
            $qb->add_constraint('name', '=', $this->argv[0]);
120 322
            $qb->add_constraint('up', '=', $this->current->id);
121
122 322
            if ($qb->count() == 0) {
123
                // last load returned ACCESS DENIED, no sense to dig deeper
124 322
                if ($qb->denied > 0) {
125
                    throw new \midcom_error_forbidden;
126
                }
127
                // allow for handler switches to work
128 322
                return;
129
            }
130
            // Set to current topic
131 3
            $this->objects[$object_url] = $qb->get_result(0);
132
        }
133
        // Remove this component from path
134 3
        array_shift($this->argv);
135
136
        // Set as current object
137 3
        $this->url = $object_url;
138 3
        $this->current = $this->objects[$object_url];
139 3
        $this->walk_topics();
140 3
    }
141
}
142