Completed
Push — master ( 1e9ef5...3740bc )
by Richard
05:53 queued 29s
created

QueryImpl::switch_run_command()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.0218

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 8
cts 9
cp 0.8889
rs 9.2
c 0
b 0
f 0
cc 4
eloc 10
nc 4
nop 2
crap 4.0218
1
<?php
2
/******************************************************************************
3
 * An implementation of dicto (scg.unibe.ch/dicto) in and for PHP.
4
 * 
5
 * Copyright (c) 2016 Richard Klees <[email protected]>
6
 *
7
 * This software is licensed under The MIT License. You should have received 
8
 * a copy of the license along with the code.
9
 */
10
11
namespace Lechimp\Dicto\Graph;
12
13
class QueryImpl implements Query {
14
    /**
15
     * @var Graph
16
     */
17
    protected $graph;
18
19
    /**
20
     * @var array[]
21
     */
22
    protected $steps;
23
24 56
    public function __construct(Graph $graph) {
25 56
        $this->graph = $graph;
26 56
        $this->steps = [];
27 56
        $this->predicate_factory = new PredicateFactory();
0 ignored issues
show
Bug introduced by
The property predicate_factory does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
28 56
    }
29
30
    /**
31
     * @inheritdocs
32
     */
33 36
    public function predicate_factory() {
34 36
        return $this->predicate_factory;
35
    }
36
37
    /**
38
     * @inheritdocs
39
     */
40 29
    public function expand(\Closure $expander) {
41 29
        $clone = clone $this;
42 29
        $clone->steps[] = ["expand", $expander];
43 29
        assert('$this->steps != $clone->steps');
44 29
        return $clone;
45
    }
46
47
    /**
48
     * @inheritdocs
49
     */
50 55
    public function extract(\Closure $extractor) {
51 55
        $clone = clone $this;
52 55
        $clone->steps[] = ["extract", $extractor];
53 55
        assert('$this->steps != $clone->steps');
54 55
        return $clone;
55
    }
56
57
    /**
58
     * @inheritdocs
59
     */
60 49
    public function filter(Predicate $predicate) {
61 49
        $clone = clone $this;
62 49
        $clone->steps[] = ["filter", $predicate];
63 49
        assert('$this->steps != $clone->steps');
64 49
        return $clone;
65
    }
66
67
    /**
68
     * @inheritdocs
69
     */
70 55
    public function run($result) {
71 55
        $steps = $this->steps;
72 55
        if (count($steps) > 0 && $steps[0][0] == "filter") {
73 49
            $nodes = $this->graph->nodes($steps[0][1]);
74 49
            array_shift($steps);
75 49
        }
76
        else {
77 6
            $nodes = $this->graph->nodes();
78
        }
79 55
        $nodes = $this->add_result($nodes, $result);
80
81 55
        foreach ($this->steps as $step) {
82 55
            $nodes = $this->switch_run_command($nodes, $step);
83 55
        }
84
85 55
        $res = array();
86 55
        while ($nodes->valid()) {
87 40
            $val = $nodes->current();
88 40
            $res[] = $val[1];
89 40
            $nodes->next();
90 40
        }
91 55
        return $res;
92
    }
93
94
    /**
95
     * @return  Iterator<[Node,mixed]>
0 ignored issues
show
Documentation introduced by
The doc-type Iterator<[Node,mixed]> could not be parsed: Expected "|" or "end of type", but got "<" at position 8. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
96
     */
97 55
    protected function switch_run_command(\Iterator $nodes, $step) {
98 55
        list($cmd,$par) = $step;
99 55
        if ($cmd == "expand") {
100 29
            return $this->run_expand($nodes, $par);
101
        }
102 55
        elseif ($cmd == "extract") {
103 55
            return $this->run_extract($nodes, $par);
104
        }
105 49
        elseif ($cmd == "filter") {
106 49
            return $this->run_filter($nodes, $par);
107
        }
108
        else {
109
            throw new \LogicException("Unknown command: $cmd");
110
        }
111
    }
112
113
    /**
114
     * @return  Iterator<[Node,mixed]>
0 ignored issues
show
Documentation introduced by
The doc-type Iterator<[Node,mixed]> could not be parsed: Expected "|" or "end of type", but got "<" at position 8. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
115
     */
116 29
    protected function run_expand(\Iterator $nodes, \Closure $clsr) {
117 29 View Code Duplication
        while ($nodes->valid()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118 26
            list($node, $result) = $nodes->current();
119
            // TODO: let closure return an Iterator too.
120 26
            foreach($clsr($node) as $new_node) {
121 21
                yield [$new_node, $result];
122 26
            }
123 26
            $nodes->next();
124 26
        }
125 29
    }
126
127
    /**
128
     * @return  Iterator<[Node,mixed]>
0 ignored issues
show
Documentation introduced by
The doc-type Iterator<[Node,mixed]> could not be parsed: Expected "|" or "end of type", but got "<" at position 8. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
129
     */
130 55
    protected function run_extract(\Iterator $nodes, \Closure $clsr) {
131 55
        while ($nodes->valid()) {
132 41
            list($node, $result) = $nodes->current();
133 41
            if (is_object($result)) {
134
                $result = clone($result);
135
            }
136 41
            $clsr($node, $result);
137 41
            yield [$node, $result];
138 41
            $nodes->next();
139 41
        }
140 55
    }
141
142
    /**
143
     * @return  Iterator<[Node,mixed]>
0 ignored issues
show
Documentation introduced by
The doc-type Iterator<[Node,mixed]> could not be parsed: Expected "|" or "end of type", but got "<" at position 8. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
144
     */
145 49
    protected function run_filter(\Iterator $nodes, Predicate $predicate) {
146 49
        $clsr = $predicate->compile();
147 49 View Code Duplication
        while ($nodes->valid()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148 47
            $val = $nodes->current();
149 47
            list($node, $result) = $val;
150 47
            if ($clsr($node, $result)) {
151 47
                yield $val;
152 47
            }
153 47
            $nodes->next();
154 47
        }
155 49
    }
156
157
    /**
158
     * @return  Iterator<[Node,mixed]>
0 ignored issues
show
Documentation introduced by
The doc-type Iterator<[Node,mixed]> could not be parsed: Expected "|" or "end of type", but got "<" at position 8. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
159
     */
160 55
    protected function add_result(\Iterator $nodes, &$result) {
161 55
        while ($nodes->valid()) {
162 52
            $node = $nodes->current();
163 52
            yield [$node, $result];
164 52
            $nodes->next();
165 52
        }
166 55
    }
167
168
    // Convenience Functions
169
170
    /**
171
     * @inheritdocs
172
     */
173 13
    public function filter_by_types(array $types) {
174
        return $this->filter($this->predicate_factory()->_custom(function(Node $n) use ($types) {
175 13
            return in_array($n->type(), $types);
176 13
        }));
177
    }
178
179
    /**
180
     * @inheritdocs
181
     */
182 24
    public function expand_relations(array $types) {
183
        return $this->expand(function(Node $n) use (&$types) {
184
            return array_filter
185 22
                ( $n->relations()
186
                , function(Relation $r) use (&$types) {
187 21
                    return in_array($r->type(), $types);
188 22
                });
189 24
        });
190
    }
191
192
    /**
193
     * @inheritdocs
194
     */
195
    public function expand_target() {
196 17
        return $this->expand(function(Relation $r) {
197 13
            return [$r->target()];
198 17
        });
199
    }
200
}
201