Builder
Administrator 7/8/2021 OOPPattern
# Description
Builder is a creational design pattern, which allows constructing complex objects step by step.
- Xây dụng 1 đối tượng phức tạp bằng cách xử dụng các đối tượng đơn giản theo từng step.
- Các đối tượng độc lập với nhau.
# Example
Build query của mysql
interface SQLQueryFactory
{
public function getSQLBuilder(): SQLQueryBuilder;
}
1
2
3
4
2
3
4
interface SQLQueryBuilder
{
public function select(string $table, array $fields): SQLQueryBuilder;
public function where(string $field, string $value, string $operator = '='): SQLQueryBuilder;
public function limit(int $start, int $offset): SQLQueryBuilder;
// +100 other SQL syntax methods...
public function getSQL(): string;
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
class MySQLQueryFactory implements SQLQueryFactory
{
public function getSQLBuilder(): SQLQueryBuilder
{
return new MySQLQueryBuilder();
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
class MySQLQueryBuilder implements SQLQueryBuilder
{
protected \stdClass $query;
protected function reset(): void
{
$this->query = new \stdClass();
}
/**
* Build a base SELECT query.
* @param string $table
* @param array $fields
* @return SQLQueryBuilder
*/
public function select(string $table, array $fields): SQLQueryBuilder
{
$this->reset();
$this->query->base = "SELECT " . implode(", ", $fields) . " FROM " . $table;
$this->query->type = 'select';
return $this;
}
/**
* Add a WHERE condition.
*
* @param string $field
* @param string $value
* @param string $operator
* @return SQLQueryBuilder
* @throws \Exception
*/
public function where(string $field, string $value, string $operator = '='): SQLQueryBuilder
{
if (!in_array($this->query->type, ['select', 'update', 'delete'])) {
throw new \Exception("WHERE can only be added to SELECT, UPDATE OR DELETE");
}
$this->query->where[] = "$field $operator '$value'";
return $this;
}
/**
* Add a LIMIT constraint.
*
* @param int $start
* @param int $offset
* @return SQLQueryBuilder
* @throws \Exception
*/
public function limit(int $start, int $offset): SQLQueryBuilder
{
if (!in_array($this->query->type, ['select'])) {
throw new \Exception("LIMIT can only be added to SELECT");
}
$this->query->limit = " LIMIT " . $start . ", " . $offset;
return $this;
}
/**
* Get the final query string.
*/
public function getSQL(): string
{
$query = $this->query;
$sql = $query->base;
if (!empty($query->where)) {
$sql .= " WHERE " . implode(' AND ', $query->where);
}
if (isset($query->limit)) {
$sql .= $query->limit;
}
$sql .= ";";
return $sql;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Usage:
$mysqlFactory = new MySQLQueryFactory();
$builder = $mysqlFactory->getSQLBuilder();
$usersQuery = $builder
->select('users', ['*'])
->where('active', true)
->limit(0, 10)
->getSQL();
1
2
3
4
5
6
7
2
3
4
5
6
7
- Create query theo từng step thay vì xử lí cùng lúc tất cả tham số (select, limit, where, ..)
- Dễ test, maintaince.
Refer: https://refactoring.guru/design-patterns/builder/php/example#example-1