Completed
Push — 2.0 ( 1160ec...acba87 )
by Vermeulen
05:15
created

anonymous//src/Sql.php$0   A

Complexity

Total Complexity 1

Size/Duplication

Total Lines 10
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 0

Importance

Changes 0
Metric Value
wmc 1
lcom 0
cbo 0
dl 0
loc 10
c 0
b 0
f 0
rs 10
1
<?php
2
3
namespace BfwSql;
4
5
use \Exception;
6
7
/**
8
 * Class to access to query writer
9
 * 
10
 * @package bfw-sql
11
 * @author Vermeulen Maxime <[email protected]>
12
 * @version 2.0
13
 */
14
class Sql
15
{
16
    /**
17
     * @const ERR_QUERY_BAD_REQUEST Exception code if the request executed
18
     * on query method have an error.
19
     */
20
    const ERR_QUERY_BAD_REQUEST = 2103001;
21
    
22
    /**
23
     * @var \BfwSql\SqlConnect $sqlConnect SqlConnect object
24
     */
25
    protected $sqlConnect;
26
    
27
    /**
28
     * @var string $prefix Tables prefix
29
     */
30
    protected $prefix = '';
31
    
32
    /**
33
     * Constructor
34
     * 
35
     * @param \BfwSql\SqlConnect $sqlConnect SqlConnect instance
36
     * 
37
     * @throws \Exception
38
     */
39
    public function __construct(\BfwSql\SqlConnect $sqlConnect)
40
    {
41
        $this->sqlConnect = $sqlConnect;
42
        $this->prefix     = $sqlConnect->getConnectionInfos()->tablePrefix;
43
    }
44
    
45
    /**
46
     * Getter to the property sqlConnect
47
     * 
48
     * @return \BfwSql\SqlConnect
49
     */
50
    public function getSqlConnect(): \BfwSql\SqlConnect
51
    {
52
        return $this->sqlConnect;
53
    }
54
    
55
    /**
56
     * Getter to the property prefix
57
     * 
58
     * @return string
59
     */
60
    public function getPrefix(): string
61
    {
62
        return $this->prefix;
63
    }
64
    
65
    /**
66
     * Get the id for the last item has been insert in database
67
     * 
68
     * @param string|null $name (default: null) Name of the sequence for the id
69
     *  Used for SGDB like PostgreSQL. Not use it for mysql.
70
     * 
71
     * @return integer
72
     */
73
    public function obtainLastInsertedId($name = null): int
74
    {
75
        return (int) $this->sqlConnect->getPDO()->lastInsertId($name);
76
    }
77
    
78
    /**
79
     * Get the id for the last item has been insert in database for a table
80
     * without auto-increment
81
     * 
82
     * @param string       $table The table name
83
     * @param string       $colId The column name for the ID
84
     * @param array        $order Columns to sort table content
85
     * @param string|array $where All where instruction used for filter content
86
     * 
87
     * @return integer
88
     */
89
    public function obtainLastInsertedIdWithoutAI(
90
        string $table,
91
        string $colId,
92
        array $order,
93
        $where = ''
94
    ): int {
95
        $req = $this->select()
0 ignored issues
show
Documentation Bug introduced by
The method from does not exist on object<BfwSql\Queries\Select>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
96
                    ->from($table, $colId)
97
                    ->limit(1);
98
    
99
        if (is_array($where)) {
100
            foreach ($where as $val) {
101
                $req->where($val);
102
            }
103
        } elseif ($where != '') {
104
            $req->where($where);
105
        }
106
        
107
        if (is_array($order)) {
108
            foreach ($order as $expr => $sort) {
109
                $req->order($expr, $sort);
110
            }
111
        }
112
        
113
        $res = $req->getExecuter()->fetchRow();
114
        $req->getExecuter()->closeCursor();
115
        
116
        if ($res) {
117
            return (int) $res[$colId];
118
        }
119
        
120
        return 0;
121
    }
122
    
123
    /**
124
     * Return a new instance of SqlSelect
125
     * 
126
     * @param string $type (default: "array") Return PHP type
127
     *  Possible value : "array" or "object"
128
     * 
129
     * @return \BfwSql\Queries\Select
130
     */
131
    public function select(string $type = 'array'): \BfwSql\Queries\Select
132
    {
133
        $usedClass       = \BfwSql\UsedClass::getInstance();
134
        $selectClassName = $usedClass->obtainClassNameToUse('QueriesSelect');
135
        
136
        return new $selectClassName($this->sqlConnect, $type);
137
    }
138
    
139
    /**
140
     * Return a new instance of SqlInsert
141
     * 
142
     * @param string $quoteStatus (default: QUOTE_ALL) Status to automatic
143
     *  quoted string value system.
144
     * 
145
     * @return \BfwSql\Queries\Insert
146
     */
147 View Code Duplication
    public function insert(
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...
148
        string $quoteStatus = \BfwSql\Helpers\Quoting::QUOTE_ALL
149
    ): \BfwSql\Queries\Insert {
150
        $usedClass       = \BfwSql\UsedClass::getInstance();
151
        $insertClassName = $usedClass->obtainClassNameToUse('QueriesInsert');
152
        
153
        return new $insertClassName($this->sqlConnect, $quoteStatus);
154
    }
155
    
156
    /**
157
     * Return a new instance of SqlUpdate
158
     * 
159
     * @param string $quoteStatus (default: QUOTE_ALL) Status to automatic
160
     *  quoted string value system.
161
     * 
162
     * @return \BfwSql\Queries\Update
163
     */
164 View Code Duplication
    public function update(
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...
165
        string $quoteStatus = \BfwSql\Helpers\Quoting::QUOTE_ALL
166
    ): \BfwSql\Queries\Update {
167
        $usedClass       = \BfwSql\UsedClass::getInstance();
168
        $updateClassName = $usedClass->obtainClassNameToUse('QueriesUpdate');
169
        
170
        return new $updateClassName($this->sqlConnect, $quoteStatus);
171
    }
172
    
173
    /**
174
     * Return a new instance of SqlDelete
175
     * 
176
     * @return \BfwSql\Queries\Delete
177
     */
178
    public function delete(): \BfwSql\Queries\Delete
179
    {
180
        $usedClass       = \BfwSql\UsedClass::getInstance();
181
        $deleteClassName = $usedClass->obtainClassNameToUse('QueriesDelete');
182
        
183
        return new $deleteClassName($this->sqlConnect);
184
    }
185
    
186
    /**
187
     * Find the first vacant id on a table and for a column
188
     * 
189
     * @param string $table  The table concerned by the request
190
     * @param string $column The id column. Must be an integer..
191
     * 
192
     * @throws \Exception If a error has been throw during the search
193
     * 
194
     * @return integer
195
     */
196
    public function createId(string $table, string $column): int
197
    {
198
        //Search the first line in the table
199
        $reqFirstLine = $this->select()
0 ignored issues
show
Documentation Bug introduced by
The method from does not exist on object<BfwSql\Queries\Select>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
200
            ->from($table, $column)
201
            ->order($column, 'ASC')
202
            ->limit(1);
203
        
204
        $resFirstLine = $reqFirstLine->getExecuter()->fetchRow();
205
        $reqFirstLine->getExecuter()->closeCursor();
206
        
207
        // If nothing in the table. First AI is 1
208
        if (!$resFirstLine) {
209
            return 1;
210
        }
211
        
212
        // If the id for the first line is > 1
213
        if ($resFirstLine[$column] > 1) {
214
            return $resFirstLine[$column] - 1;
215
        }
216
        
217
        //First line have ID=1, we search from the end
218
        $reqLastLine = $this->select()
0 ignored issues
show
Documentation Bug introduced by
The method from does not exist on object<BfwSql\Queries\Select>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
219
            ->from($table, $column)
220
            ->order($column, 'DESC')
221
            ->limit(1);
222
        
223
        $resLastLine = $reqLastLine->getExecuter()->fetchRow();
224
        $reqLastLine->getExecuter()->closeCursor();
225
226
        //Get the last ID and add 1
227
        return $resLastLine[$column] + 1;
228
    }
229
    
230
    /**
231
     * Run the query in parameter 
232
     * 
233
     * @param string $request The request to run
234
     * 
235
     * @throws \Exception If the request has failed
236
     * 
237
     * @return \PDOStatement
238
     */
239
    public function query(string $request): \PDOStatement
240
    {
241
        $this->sqlConnect->upNbQuery();
242
        
243
        $req   = $this->sqlConnect->getPDO()->query($request);
244
        $error = $this->sqlConnect->getPDO()->errorInfo();
245
        
246
        $app     = \BFW\Application::getInstance();
247
        $subject = $app->getSubjectList()->getSubjectByName('bfw-sql');
248
        $subject->addNotification(
249
            'user query',
250
            new class ($request, $error) {
251
                public $request = '';
252
                public $error = [];
253
                
254
                public function __construct($request, $error)
255
                {
256
                    $this->request = $request;
257
                    $this->error   = $error;
258
                }
259
            }
260
        );
261
        
262
        if (
263
            !$req
264
            && $error[0] !== null
265
            && $error[0] !== '00000'
266
            && isset($error[2])
267
        ) {
268
            throw new Exception(
269
                $error[2],
270
                self::ERR_QUERY_BAD_REQUEST
271
            );
272
        }
273
        
274
        return $req;
275
    }
276
}
277