Completed
Pull Request — release-2.1 (#4446)
by Mathias
12:43
created

postgres_cache::housekeeping()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Simple Machines Forum (SMF)
5
 *
6
 * @package SMF
7
 * @author Simple Machines http://www.simplemachines.org
8
 * @copyright 2018 Simple Machines and individual contributors
9
 * @license http://www.simplemachines.org/about/smf/license.php BSD
10
 *
11
 * @version 2.1 Beta 4
12
 */
13
14
if (!defined('SMF'))
15
	die('Hacking attempt...');
16
17
/**
18
 * PostgreSQL Cache API class
19
 * @package cacheAPI
20
 */
21
class postgres_cache extends cache_api
22
{
23
	/**
24
	 * @var false|resource of the pg_prepare from get_data.
25
	 */
26
	private $pg_get_data_prep;
27
28
	/**
29
	 * @var false|resource of the pg_prepare from put_data.
30
	 */
31
	private $pg_put_data_prep;
32
33
	public function __construct()
34
	{
35
		parent::__construct();
36
	}
37
38
	/**
39
	 * {@inheritDoc}
40
	 */
41
	public function connect()
42
	{
43
		global $db_prefix, $db_connection;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
44
45
		pg_prepare($db_connection, '', 'SELECT 1
46
			FROM   pg_tables
47
			WHERE  schemaname = $1
48
			AND    tablename = $2');
49
50
		$result = pg_execute($db_connection, '', array('public', $db_prefix . 'cache'));
51
52
		if (pg_affected_rows($result) === 0)
53
			pg_query($db_connection, 'CREATE UNLOGGED TABLE ' . $db_prefix . 'cache (key text, value text, ttl bigint, PRIMARY KEY (key))');			
54
	}
55
56
	/**
57
	 * {@inheritDoc}
58
	 */
59
	public function isSupported($test = false)
60
	{
61
		global $smcFunc, $db_connection;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
62
63
		if ($smcFunc['db_title'] !== 'PostgreSQL')
64
			return false;
65
66
		$result = pg_query($db_connection, 'SHOW server_version_num');
67
		$res = pg_fetch_assoc($result);
68
69
		if ($res['server_version_num'] < 90500)
70
			return false;
71
72
		return $test ? true : parent::isSupported();
73
	}
74
75
	/**
76
	 * {@inheritDoc}
77
	 */
78
	public function getData($key, $ttl = null)
79
	{
80
		global $db_prefix, $db_connection;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
81
82
		$ttl = time() - $ttl;
83
84
		if (empty($this->pg_get_data_prep))
85
			$this->pg_get_data_prep = pg_prepare($db_connection, 'smf_cache_get_data', 'SELECT value FROM ' . $db_prefix . 'cache WHERE key = $1 AND ttl >= $2 LIMIT 1');
86
87
		$result = pg_execute($db_connection, 'smf_cache_get_data', array($key, $ttl));
88
89
		if (pg_affected_rows($result) === 0)
90
			return null;
91
92
		$res = pg_fetch_assoc($result);
93
94
		return $res['value'];
95
	}
96
97
	/**
98
	 * {@inheritDoc}
99
	 */
100
	public function putData($key, $value, $ttl = null)
101
	{
102
		global  $db_prefix, $db_connection;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
103
104
		if (!isset($value))
105
			$value = '';
106
107
		$ttl = time() + $ttl;
108
109
		if (empty($this->pg_put_data_prep))
110
			$this->pg_put_data_prep = pg_prepare($db_connection, 'smf_cache_put_data',
111
				'INSERT INTO ' . $db_prefix . 'cache(key,value,ttl) VALUES($1,$2,$3)
112
				ON CONFLICT(key) DO UPDATE SET value = excluded.value, ttl = excluded.ttl'
113
			);
114
115
		$result = pg_execute($db_connection, 'smf_cache_put_data', array($key, $value, $ttl));
116
117
		if (pg_affected_rows($result) > 0)
0 ignored issues
show
Coding Style introduced by
The if-else statement can be simplified to return pg_affected_rows($result) > 0;.
Loading history...
118
			return true;
119
		else
120
			return false;
121
	}
122
123
	/**
124
	 * {@inheritDoc}
125
	 */
126
	public function cleanCache($type = '')
127
	{
128
		global $smcFunc;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
129
130
		$smcFunc['db_query']('',
131
				'TRUNCATE TABLE {db_prefix}cache',
132
				array()
133
			);
134
135
		return true;
136
	}
137
138
	/**
139
	 * {@inheritDoc}
140
	 */
141
	public function getVersion()
142
	{
143
		global $smcFunc;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
144
145
		return $smcFunc['db_server_info']();
146
	}
147
	
148
	/**
149
	 * {@inheritDoc}
150
	 */
151
	public function housekeeping()
152
	{
153
		$this->createTempTable();
154
		$this->cleanCache();
155
		$this->retrieveData();
156
		$this->deleteTempTable();
157
	}
158
	
159
	/**
160
	 * Create the temp table of valid data.
161
	 * 
162
	 * @return void
163
	 */
164
	private function createTempTable()
165
	{
166
		global $db_connection, $db_prefix;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
167
		
168
		pg_query($db_connection, 'CREATE LOCAL TEMP TABLE IF NOT EXISTS ' . $db_prefix . 'cache_tmp AS SELECT * FROM ' . $db_prefix . 'cache WHERE ttl >= ' . time() );
169
	}
170
	
171
	/**
172
	 * Delete the temp table.
173
	 * 
174
	 * @return void
175
	 */
176
	private function deleteTempTable()
177
	{
178
		global $db_connection, $db_prefix;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
179
		
180
		pg_query($db_connection, 'DROP TABLE IF EXISTS ' . $db_prefix . 'cache_tmp');
181
	}
182
	
183
	/**
184
	 * Retrieve the valid data from temp table.
185
	 * 
186
	 * @return void
187
	 */
188
	private function retrieveData()
189
	{
190
		global $db_connection, $db_prefix;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
191
		
192
		pg_query($db_connection, 'INSERT INTO ' . $db_prefix . 'cache SELECT * FROM '. $db_prefix . 'cache_tmp ON CONFLICT DO NOTHING');
193
	}
194
}
195
196
?>