This repository has been archived by the owner on Aug 6, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathKeyValueTable.php
165 lines (146 loc) · 3.98 KB
/
KeyValueTable.php
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<?php
/**
* KeyValueTable
*
* This is a simple key-value storage that creates it own database table
* to save the data to a MySQL database.
*
* Requires a PDO object with access to a selected database.
* The database user needs the rights to SHOW, CREATE, SELECT, INSERT and UPDATE.
* Table column `value` is not nullable. If some function returns NULL,
* the requested key was not set.
*
* Any values that are not scalar (e.g. arrays, objects) will be stored as JSON encoded string.
*
* @example For usage examples see the IterableCountable class documentation.
*/
class KeyValueTable extends IterableCountable
{
/**
* @var PDO
*/
private $database;
/**
* @var string the used table name
*/
protected $table;
/**
*
* @param \PDO $database
* @param string $table Used as table name for this object; if empty a random sha1 hex will be used instead.
* @param boolean $autoload Load all the available data from the the DB table into the instance on instantiation.
*/
public function __construct( \PDO &$database, $table = null, $autoload = true )
{
$this->database = $database;
if( !empty( $table ) )
{
$this->table = trim( $this->database->quote( $table ), '\'' );
}
else
{
$this->table = sha1( uniqid( mt_rand(), true ) );
}
/* check if table exists */
$tableExistsStmt = $this->database->prepare( sprintf( 'SHOW TABLES LIKE \'%s\'', $this->table ) );
$tableExistsStmt->execute();
if( $tableExistsStmt->rowCount() <= 0 )
{
/* no, create it */
$this->setup();
}
elseif( $autoload == true )
{
/* load all data from database into object */
$this->load();
}
}
/**
* Creates the Iterable equivalent as MySQL table,
* using `key` and `value` as columns, where `key` is the PRIMARY index.
*
* @return boolean
*/
private function setup()
{
$createStatement = 'CREATE TABLE `%s` (
`key` VARCHAR( 255 ) NOT NULL,
`value` BLOB NOT NULL,
PRIMARY KEY ( `key` )
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;';
return false !== $this->database->exec( sprintf( $createStatement, $this->table ) );
}
protected function load()
{
$selectSql = 'SELECT `key`, `value` FROM `%s`';
$selectStmt = $this->database->prepare( sprintf( $selectSql, $this->table ) );
if( $selectStmt->execute() && $selectStmt->rowCount() > 0 )
{
while( $row = $selectStmt->fetch( \PDO::FETCH_ASSOC ) )
{
parent::set( $row['key'], $row['value'] );
}
}
}
/**
* Returns the table name; useful if the table name was generated.
*
* @return string
*/
public function getTable()
{
return $this->table;
}
/**
* Insert or update a value represented by a key.
*
* @param string|int $key
* @param mixed $value
* @return boolean|KeyValueTable
*/
public function set( $key, $value )
{
$insertUpdateSql = 'INSERT INTO `%s` (`key`, `value`)'
. ' VALUES (:key, :value)'
. ' ON DUPLICATE KEY UPDATE `value` = :update_value';
$stmt = $this->database->prepare( sprintf( $insertUpdateSql, $this->table ) );
$stmt->bindValue( ':key', $key );
if( !is_scalar( $value ) )
{
$insertValue = 'json:' . json_encode( $value );
}
$stmt->bindValue( ':value', $insertValue );
$stmt->bindValue( ':update_value', $insertValue );
if( $stmt->execute() == true )
{
parent::set( $key, $value );
}
return $this;
}
public function get( $key )
{
$value = parent::get( $key );
if( substr( $value, 0, 5 ) == 'json:' )
{
$value = json_decode( substr( $value, 5 ) );
}
return $value;
}
/**
* unset()
*
* @param string|int $key
* @return boolean
*/
public function remove( $key )
{
$deleteSql = 'DELETE FROM `%s` WHERE `key` = :key';
$deleteStmt = $this->database->prepare( sprintf( $deleteSql, $this->table ) );
$deleteStmt->bindValue( ':key', $key );
if( $deleteStmt->execute() && $deleteStmt->rowCount() > 0 )
{
parent::remove( $key );
}
return $this;
}
}