Completed
Push — master ( 59b3e2...6dd6b9 )
by Andrii
15:38
created

Query   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 168
Duplicated Lines 14.88 %

Coupling/Cohesion

Components 3
Dependencies 1

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 32
lcom 3
cbo 1
dl 25
loc 168
rs 9.6
c 1
b 0
f 0
ccs 0
cts 139
cp 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A instantiate() 0 6 1
A createCommand() 0 10 2
A one() 0 4 1
B all() 5 19 5
A searchAll() 0 4 1
A search() 0 4 1
A delete() 0 4 1
A count() 0 6 1
A exists() 0 4 1
A action() 0 6 1
A addAction() 0 8 2
A addOption() 0 8 2
A getOption() 0 4 2
A options() 0 6 1
A addOptions() 0 8 2
A body() 0 6 1
A innerJoin() 0 6 1
A fields() 10 10 3
A source() 10 10 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Tools to use API as ActiveRecord for Yii2
4
 *
5
 * @link      https://github.com/hiqdev/yii2-hiart
6
 * @package   yii2-hiart
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2015-2017, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\hiart;
12
13
use yii\db\QueryInterface;
14
15
/**
16
 * Query represents API query in a way that is independent from a concrete API.
17
 * Holds API query information:
18
 * - general query data
19
 *      - action: action to be performed with this query, e.g. search, insert, update, delete
20
 *      - options: other additional options, like
21
 *          - raw: do not decode response
22
 *          - batch: batch(bulk) request
23
 *          - timeout, ...
24
 * - insert/update query data
25
 *      - body: insert or update data
26
 * - select query data
27
 *      - select: fields to select
28
 *      - count: marks count query
29
 *      - from: entity being queried, e.g. user
30
 *      - join: data how to join with other entities
31
 * - other standard query options provided with QueryTrait:
32
 *      - where, limit, offset, orderBy, indexBy.
33
 */
34
class Query extends \yii\db\Query implements QueryInterface
35
{
36
    /**
37
     * @var string action that this query performs
38
     */
39
    public $action;
40
41
    /**
42
     * @var array query options e.g. raw, batch
43
     */
44
    public $options = [];
45
46
    public $count;
47
48
    public $body = [];
49
50
    public static function instantiate($action, $from, array $options = [])
51
    {
52
        $query = new static();
53
54
        return $query->action($action)->from($from)->options($options);
55
    }
56
57
    public function createCommand($db = null)
58
    {
59
        if ($db === null) {
60
            throw new \Exception('no db given to Query::createCommand');
61
        }
62
63
        $commandConfig = $db->getQueryBuilder()->build($this);
64
65
        return $db->createCommand($commandConfig);
66
    }
67
68
    public function one($db = null)
69
    {
70
        return $this->limit(1)->addOption('batch', false)->search();
71
    }
72
73
    public function all($db = null)
74
    {
75
        $rows = $this->searchAll();
76
77
        if (!empty($rows) && $this->indexBy !== null) {
78
            $result = [];
79
            foreach ($rows as $row) {
80 View Code Duplication
                if ($this->indexBy instanceof \Closure) {
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...
81
                    $key = call_user_func($this->indexBy, $row);
82
                } else {
83
                    $key = $row[$this->indexBy];
84
                }
85
                $result[$key] = $row;
86
            }
87
            $rows = $result;
88
        }
89
90
        return $rows;
91
    }
92
93
    public function searchAll($db = null)
0 ignored issues
show
Unused Code introduced by
The parameter $db is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
94
    {
95
        return $this->addOption('batch', true)->search();
96
    }
97
98
    public function search($db = null)
99
    {
100
        return $this->createCommand($db)->search();
101
    }
102
103
    public function delete($db = null, $options = [])
104
    {
105
        return $this->createCommand($db)->deleteByQuery($options);
106
    }
107
108
    public function count($q = '*', $db = null)
109
    {
110
        $this->count = $q;
111
112
        return (int) $this->searchAll();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return (int) $this->searchAll(); (integer) is incompatible with the return type of the parent method yii\db\Query::count of type string|null|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
113
    }
114
115
    public function exists($db = null)
116
    {
117
        return !empty(self::one($db));
118
    }
119
120
    public function action($action)
121
    {
122
        $this->action = $action;
123
124
        return $this;
125
    }
126
127
    public function addAction($action)
128
    {
129
        if (empty($this->action)) {
130
            $this->action = $action;
131
        }
132
133
        return $this;
134
    }
135
136
    public function addOption($name, $value)
137
    {
138
        if (!isset($this->options[$name])) {
139
            $this->options[$name] = $value;
140
        }
141
142
        return $this;
143
    }
144
145
    public function getOption($name)
146
    {
147
        return isset($this->options[$name]) ? $this->options[$name] : null;
148
    }
149
150
    public function options($options)
151
    {
152
        $this->options = $options;
153
154
        return $this;
155
    }
156
157
    public function addOptions($options)
158
    {
159
        if (!empty($options)) {
160
            $this->options = array_merge($this->options, $options);
161
        }
162
163
        return $this;
164
    }
165
166
    public function body($body)
167
    {
168
        $this->body = $body;
169
170
        return $this;
171
    }
172
173
    public function innerJoin($table, $on = '', $params = [])
174
    {
175
        $this->join[] = (array) $table;
176
177
        return $this;
178
    }
179
180 View Code Duplication
    public function fields($fields)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
181
    {
182
        if (is_array($fields) || $fields === null) {
183
            $this->fields = $fields;
0 ignored issues
show
Documentation introduced by
The property fields does not exist on object<hiqdev\hiart\Query>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
184
        } else {
185
            $this->fields = func_get_args();
0 ignored issues
show
Documentation introduced by
The property fields does not exist on object<hiqdev\hiart\Query>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
186
        }
187
188
        return $this;
189
    }
190
191 View Code Duplication
    public function source($source)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
192
    {
193
        if (is_array($source) || $source === null) {
194
            $this->source = $source;
0 ignored issues
show
Documentation introduced by
The property source does not exist on object<hiqdev\hiart\Query>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
195
        } else {
196
            $this->source = func_get_args();
0 ignored issues
show
Documentation introduced by
The property source does not exist on object<hiqdev\hiart\Query>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
197
        }
198
199
        return $this;
200
    }
201
}
202