Completed
Push — master ( 1a5eaf...51a843 )
by Richard
05:35
created

Relation::insert_relation_into()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 14
ccs 13
cts 13
cp 1
rs 9.4285
cc 3
eloc 10
nc 3
nop 3
crap 3
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 licence along with the code.
9
 */
10
11
namespace Lechimp\Dicto\Rules;
12
13
use Lechimp\Dicto\Definition as Def;
14
use Lechimp\Dicto\Indexer\Insert;
15
use Lechimp\Dicto\Indexer\Location;
16
use Lechimp\Dicto\Analysis\Query;
17
use Lechimp\Dicto\Analysis\Violation;
18
use \Lechimp\Dicto\Variables\Variable;
19
20
/**
21
 * This is a rule that checks a relation between two entities
22
 * in the code.
23
 */
24
abstract class Relation extends Schema {
25
    /**
26
     * @inheritdoc
27
     */
28 146
    public function fluid_interface(Def\RT $rt, $name, $mode, array $arguments) {
29 146
        if (count($arguments) != 0) {
30
            throw new \InvalidArgumentException(
31
                "No arguments are allowed when using a relational rule schema.");
32
        }
33 146
        return new Def\Fluid\Relation($rt, $name, $mode, $this);
34
    }
35
36 188
    public function check_arguments(array $arguments) {
37 188
         if (count($arguments) != 1) {
38
            throw new \InvalidArgumentException(
39
                "One argument is required when using a relational rule schema.");
40
        }
41 188
       if (!($arguments[0] instanceof Variable)) {
42
            throw new \InvalidArgumentException(
43
                "Expected variable, got '".get_class($arguments[0])."' when using a relational schema.");
44
        }
45
46 188
    }
47
48
    /**
49
     * @inheritdoc
50
     */
51 3
    public function pprint(Rule $rule) {
52 3
        return $this->printable_name()." ".$rule->argument(0)->name();
53
    }
54
55
    /**
56
     * @inheritdoc
57
     */
58 37
    public function compile(Query $query, Rule $rule) {
59 37
        $builder = $query->builder();
60 37
        $b = $builder->expr();
61 37
        $mode = $rule->mode();
62 37
        $entity = $rule->checked_on();
63 37
        $reference = $rule->argument(0);
64 37
        if ($mode == Rule::MODE_CANNOT || $mode == Rule::MODE_ONLY_CAN) {
65
            return $builder
66 29
                ->select
67 29
                    ( "rel.entity_id as entity_id"
68 29
                    , "rel.reference_id as reference_id"
69 29
                    , "r.file as file"
70 29
                    , "r.line as line"
71 29
                    , "src.source as source"
72 29
                    )
73 29
                ->from($query->relations_table(), "rel")
74 29
                ->innerJoin("rel", $query->entity_table(), "e", "rel.entity_id = e.id")
75 29
                ->innerJoin("rel", $query->reference_table(), "r", "rel.reference_id = r.id")
76
                ->innerJoin
77 29
                    ( "rel", $query->source_file_table(), "src"
78 29
                    , $b->andX
79 29
                        ( $b->eq("src.line", "r.line")
80 29
                        , $b->eq("src.name", "r.file")
81 29
                        )
82 29
                    )
83
                ->where
84 29
                    ( $b->eq("rel.name", $b->literal($this->name()))
85 29
                    , $query->compile_var("e", $entity)
86 29
                    , $query->compile_var("r", $reference)
87 29
                    )
88 29
                ->execute();
89
        }
90 8
        if ($mode == Rule::MODE_MUST) {
91
            return $builder
92 8
                ->select
93 8
                    ( "e.id as entity_id"
94 8
                    , "e.file as file"
95 8
                    , "e.start_line as line"
96 8
                    , "src.source as source"
97 8
                    )
98 8
                ->from($query->entity_table(), "e")
99
                ->leftJoin
100 8
                    ("e", $query->relations_table(), "rel"
101 8
                    , $b->andX
102 8
                        ( $b->eq("rel.name", $b->literal($this->name()))
103 8
                        , $b->eq("rel.entity_id", "e.id")
104 8
                        )
105 8
                    )
106
                ->leftJoin
107 8
                    ("rel", $query->reference_table(), "r"
108 8
                    , $b->andX
109 8
                        ( $b->eq("rel.reference_id", "r.id")
110 8
                        , $query->compile_var("r", $reference)
111 8
                        )
112 8
                    )
113
                ->innerJoin
114 8
                    ( "e", $query->source_file_table(), "src"
115 8
                    , $b->andX
116 8
                        ( $b->eq("src.line", "e.start_line")
117 8
                        , $b->eq("src.name", "e.file")
118 8
                        )
119 8
                    )
120
121
                ->where
122 8
                    ( $query->compile_var("e", $entity)
123 8
                    , $b->isNull("r.id")
124 8
                    )
125 8
                ->execute();
126
        }
127
        throw new \LogicException("Unknown rule mode: '$mode'");
128
    }
129
130
    /**
131
     * Insert this relation somewhere, where it is recorded for all
132
     * entities that the current location is in, except for files.
133
     *
134
     * @param   Insert      $insert
135
     * @param   Location    $location
136
     * @param   int         $ref_id
137
     * @return  null
138
     */
139 17
    protected function insert_relation_into(Insert $insert, Location $location, $ref_id) {
140 17
        assert('is_int($ref_id)');
141 17
        foreach ($location->in_entities() as $entity) {
142 17
            if ($entity[0] == Variable::FILE_TYPE) {
143 17
                continue;
144
            }
145 17
            $insert->relation
146 17
                ( $this->name()
147 17
                , $entity[1]
148 17
                , $ref_id
149 17
                , $location->file_path()
0 ignored issues
show
Unused Code introduced by
The call to Insert::relation() has too many arguments starting with $location->file_path().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
150 17
                );
151 17
        }
152 17
    }
153
}
154