Completed
Push — master ( 46dbb7...9c8538 )
by Hong
02:48
created

Builder::delete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
/**
3
 * Phossa Project
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  Library
8
 * @package   Phossa2\Query
9
 * @copyright Copyright (c) 2016 phossa.com
10
 * @license   http://mit-license.org/ MIT License
11
 * @link      http://www.phossa.com/
12
 */
13
/*# declare(strict_types=1); */
14
15
namespace Phossa2\Query;
16
17
use Phossa2\Query\Misc\Raw;
18
use Phossa2\Query\Dialect\Mysql;
19
use Phossa2\Query\Misc\Expression;
20
use Phossa2\Shared\Base\ObjectAbstract;
21
use Phossa2\Query\Traits\SettingsAwareTrait;
22
use Phossa2\Query\Traits\DialectAwareTrait;
23
use Phossa2\Query\Traits\ParameterAwareTrait;
24
use Phossa2\Query\Interfaces\BuilderInterface;
25
use Phossa2\Query\Interfaces\DialectInterface;
26
use Phossa2\Query\Interfaces\StatementInterface;
27
use Phossa2\Query\Interfaces\Statement\UnionStatementInterface;
28
use Phossa2\Query\Interfaces\Statement\SelectStatementInterface;
29
use Phossa2\Query\Interfaces\Statement\InsertStatementInterface;
30
use Phossa2\Query\Interfaces\Statement\UpdateStatementInterface;
31
use Phossa2\Query\Interfaces\Statement\DeleteStatementInterface;
32
33
/**
34
 * Builder
35
 *
36
 * @package Phossa2\Query
37
 * @author  Hong Zhang <[email protected]>
38
 * @see     ObjectAbstract
39
 * @see     BuilderInterface
40
 * @see     StatementInterface
41
 * @see     SelectStatementInterface
42
 * @see     InsertStatementInterface
43
 * @see     UnionStatementInterface
44
 * @see     UpdateStatementInterface
45
 * @see     DeleteStatementInterface
46
 * @version 2.0.0
47
 * @since   2.0.0 added
48
 */
49
class Builder extends ObjectAbstract implements BuilderInterface
50
{
51
    use DialectAwareTrait, SettingsAwareTrait, ParameterAwareTrait;
52
53
    /**
54
     * tables
55
     *
56
     * @var    array
57
     * @access protected
58
     */
59
    protected $tables = [];
60
61
    /**
62
     * Constructor
63
     *
64
     * ```php
65
     * // builder with default table `users` and Mysql dialect
66
     * $users = new Builder('users', new Mysql())
67
     *
68
     * // builder with defult tables:  `users` and `accounts` AS `a`
69
     * $builder = new Builder(['users', 'accounts' => 'a'])
70
     *
71
     * // change default settings
72
     * $builder = new Builder('users', new Mysql(), ['autoQuote' => false]);
73
     * ```
74
     *
75
     * @param  string|array $table table[s] to build upon
76
     * @param  DialectInterface $dialect default dialect is `Mysql`
77
     * @param  array $settings builder settings
78
     * @access public
79
     */
80
    public function __construct(
81
        $table = '',
82
        DialectInterface $dialect = null,
83
        array $settings = []
84
    ) {
85
        $this
86
            ->initParameter()
87
            ->setSettings(array_replace($this->defaultSettings(), $settings))
88
            ->setDialect($dialect)
89
            ->table($table);
90
    }
91
92
    /**
93
     * Change table[s]
94
     *
95
     * @param  $table change to table[s]
96
     * @return $this
97
     * @access public
98
     */
99
    public function __invoke($table)
100
    {
101
        return $this->table($table);
102
    }
103
104
    /**
105
     * {@inheritDoc}
106
     */
107
    public function expr()/*# : ExpressionInterface */
108
    {
109
        return new Expression($this);
110
    }
111
112
    /**
113
     * {@inheritDoc}
114
     */
115
    public function raw(
116
        /*# string */ $string,
117
        array $values = []
118
    )/*# : OutputInterface */ {
119
        if (!empty($values)) {
120
            $string = $this->getParameter()->replaceQuestionMark($string, $values);
121
        }
122
        return new Raw($string);
123
    }
124
125
    /**
126
     * If has existing tables, return a new instance with provided table[s]
127
     *
128
     * {@inheritDoc}
129
     */
130
    public function table($table, /*# string */ $alias = '')
131
    {
132
        $tbl = $this->fixTable($table, $alias);
133
        $clone = [] === $this->tables ? $this : clone $this;
134
        $clone->tables = $tbl;
135
        return $clone;
136
    }
137
138
    /**
139
     * Append to existing tables
140
     *
141
     * {@inheritDoc}
142
     */
143
    public function from($table, /*# string */ $alias = '')
144
    {
145
        $tbl = $this->fixTable($table, $alias);
146
        $this->tables = array_merge($this->tables, $tbl);
147
        return $this;
148
    }
149
150
    /**
151
     * {@inheritDoc}
152
     */
153
    public function select()/*# : SelectStatementInterface */
154
    {
155
        /* @var SelectStatementInterface $select */
156
        $select = $this->getDialect()->select($this);
157
        return $select->table($this->tables)->col(func_get_args());
158
    }
159
160
    /**
161
     * {@inheritDoc}
162
     */
163
    public function insert(array $values = [])/*# : InsertStatementInterface */
164
    {
165
        /* @var InsertStatementInterface $insert */
166
        $insert = $this->getDialect()->insert($this);
167
        return $insert->into(current($this->tables))->set($values);
168
    }
169
170
    /**
171
     * {@inheritDoc}
172
     */
173
    public function replace(array $values = [])/*# : InsertStatementInterface */
174
    {
175
        /* @var InsertStatementInterface $insert */
176
        $replace = $this->getDialect()->replace($this);
177
        return $replace->into(current($this->tables))->set($values);
178
    }
179
180
    /**
181
     * {@inheritDoc}
182
     */
183
    public function update(array $values = [])/*# : UpdateStatementInterface */
184
    {
185
        /* @var UpdateStatementInterface $update */
186
        $update = $this->getDialect()->update($this);
187
        return $update->from(current($this->tables))->set($values);
188
    }
189
190
    /**
191
     * {@inheritDoc}
192
     */
193
    public function delete()/*# : DeleteStatementInterface */
194
    {
195
        /* @var DeleteStatementInterface $delete */
196
        $delete = $this->getDialect()->delete($this);
197
        return $delete->from(current($this->tables))->col(func_get_args());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Phossa2\Query\Interfaces...eleteStatementInterface as the method col() does only exist in the following implementations of said interface: Phossa2\Query\Dialect\Mysql\Delete.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
198
    }
199
200
    /**
201
     * {@inheritDoc}
202
     */
203
    public function union()/*# : UnionStatementInterface */
204
    {
205
        /* @var UnionStatementInterface $union */
206
        $union = $this->getDialect()->union($this);
207
        if (func_num_args() > 0) { // acception variable parameters
208
            $args = func_get_args();
209
            foreach ($args as $arg) {
210
                $union->union($arg);
211
            }
212
        }
213
        return $union;
214
    }
215
216
    /**
217
     * Convert to [$table => alias] or [$table]
218
     *
219
     * @param  string|string[] $table
220
     * @param  string $alias
221
     * @return array
222
     * @access protected
223
     */
224
    protected function fixTable(
225
        $table,
226
        /*# string */ $alias = ''
227
    )/*# : array */ {
228
        if (empty($table)) {
229
            $table = [];
230
        } elseif (!is_array($table)) {
231
            $table = empty($alias) ? [$table] : [$table => $alias];
232
        }
233
        return $table;
234
    }
235
236
    /**
237
     * Builder default settings
238
     *
239
     * @return array
240
     * @access protected
241
     */
242
    protected function defaultSettings()/*# : array */
243
    {
244
        return [
245
            'autoQuote' => true,
246
            'positionedParam' => false,
247
            'namedParam' => false,
248
            'seperator' => ' ',
249
            'indent' => '',
250
            'escapeFunction' => null,
251
            'useNullAsDefault' => false,
252
        ];
253
    }
254
}
255