Caching stuff.

This commit is contained in:
flash 2018-07-16 00:39:39 +02:00
parent d52cb3af63
commit af4ec2ac45
8 changed files with 226 additions and 45 deletions

View file

@ -135,6 +135,7 @@ if (PHP_SAPI === 'cli') {
exit;
}
$app->startCache();
$app->startTemplating();
$tpl = $app->getTemplating();

View file

@ -1,11 +1,11 @@
<?php
use Misuzu\Cache;
use Misuzu\Database;
require_once __DIR__ . '/../misuzu.php';
$config = $app->getConfig();
$tpl = $app->getTemplating();
$db = Database::connection();
if ($config->get('Site', 'embed_linked_data', 'bool', false)) {
$tpl->vars([
@ -17,7 +17,7 @@ if ($config->get('Site', 'embed_linked_data', 'bool', false)) {
]);
}
$featuredNews = $db->query('
$news = Database::query('
SELECT
p.`post_id`, p.`post_title`, p.`post_text`, p.`created_at`,
u.`user_id`, u.`username`,
@ -32,46 +32,49 @@ $featuredNews = $db->query('
LIMIT 3
')->fetchAll(PDO::FETCH_ASSOC);
$usersCount = (int)$db->query('
SELECT COUNT(`user_id`)
FROM `msz_users`
')->fetchColumn();
$statistics = Cache::instance()->get('index:stats:v1', function () {
return [
'users' => (int)Database::query('
SELECT COUNT(`user_id`)
FROM `msz_users`
')->fetchColumn(),
'lastUser' => Database::query('
SELECT
u.`user_id`, u.`username`, u.`created_at`,
COALESCE(r.`role_colour`, CAST(0x40000000 AS UNSIGNED)) as `user_colour`
FROM `msz_users` as u
LEFT JOIN `msz_roles` as r
ON r.`role_id` = u.`display_role`
ORDER BY u.`user_id` DESC
LIMIT 1
')->fetch(PDO::FETCH_ASSOC),
];
}, 10800);
$lastUser = $db->query('
SELECT
u.`user_id`, u.`username`, u.`created_at`,
COALESCE(r.`role_colour`, CAST(0x40000000 AS UNSIGNED)) as `user_colour`
FROM `msz_users` as u
LEFT JOIN `msz_roles` as r
ON r.`role_id` = u.`display_role`
ORDER BY u.`user_id` DESC
LIMIT 1
')->fetch(PDO::FETCH_ASSOC);
$featuredChangelog = $db->query('
SELECT
c.`change_id`, c.`change_log`,
a.`action_name`, a.`action_colour`, a.`action_class`,
DATE(`change_created`) as `change_date`,
!ISNULL(c.`change_text`) as `change_has_text`
FROM `msz_changelog_changes` as c
LEFT JOIN `msz_changelog_actions` as a
ON a.`action_id` = c.`action_id`
WHERE DATE(c.`change_created`) >= (
SELECT DATE(`change_created`)
FROM `msz_changelog_changes`
GROUP BY DATE(`change_created`)
ORDER BY `change_created` DESC
LIMIT 2, 1
)
ORDER BY c.`change_created` DESC
')->fetchAll(PDO::FETCH_ASSOC);
//var_dump(Database::connection()->query('SHOW SESSION STATUS LIKE "Questions"')->fetch()['Value']);
$changelog = Cache::instance()->get('index:changelog:v1', function () {
return Database::query('
SELECT
c.`change_id`, c.`change_log`,
a.`action_name`, a.`action_colour`, a.`action_class`,
DATE(`change_created`) as `change_date`,
!ISNULL(c.`change_text`) as `change_has_text`
FROM `msz_changelog_changes` as c
LEFT JOIN `msz_changelog_actions` as a
ON a.`action_id` = c.`action_id`
WHERE DATE(c.`change_created`) >= (
SELECT DATE(`change_created`)
FROM `msz_changelog_changes`
GROUP BY DATE(`change_created`)
ORDER BY `change_created` DESC
LIMIT 2, 1
)
ORDER BY c.`change_created` DESC
')->fetchAll(PDO::FETCH_ASSOC);
}, 1800);
echo $tpl->render('home.index', [
'users_count' => $usersCount,
'last_user' => $lastUser,
'featured_changelog' => $featuredChangelog,
'featured_news' => $featuredNews,
'users_count' => $statistics['users'],
'last_user' => $statistics['lastUser'],
'featured_changelog' => $changelog,
'featured_news' => $news,
]);

View file

@ -217,12 +217,30 @@ class Application extends ApplicationBase
public function startDatabase(): void
{
if (Database::hasInstance()) {
throw new UnexpectedValueException('Database module has already been started.');
throw new UnexpectedValueException('Database has already been started.');
}
new Database($this->configInstance, self::DATABASE_CONNECTIONS[0]);
}
/**
* Sets up the caching stuff.
*/
public function startCache(): void
{
if (Cache::hasInstance()) {
throw new UnexpectedValueException('Cache has already been started.');
}
new Cache(
$this->configInstance->get('Cache', 'host', 'string', null),
$this->configInstance->get('Cache', 'port', 'int', null),
$this->configInstance->get('Cache', 'database', 'int', null),
$this->configInstance->get('Cache', 'password', 'string', null),
$this->configInstance->get('Cache', 'prefix', 'string', '')
);
}
/**
* Sets up the templating engine module.
*/

127
src/Cache.php Normal file
View file

@ -0,0 +1,127 @@
<?php
namespace Misuzu;
use Misuzu\Config\ConfigManager;
use Redis;
use InvalidArgumentException;
use UnexpectedValueException;
final class Cache
{
/**
* @var Cache
*/
private static $instance;
private $redis;
public static function instance(): Cache
{
if (!self::hasInstance()) {
throw new UnexpectedValueException('No instance of Cache exists yet.');
}
return self::$instance;
}
public function getRedis(): Redis
{
return $this->redis;
}
public static function hasInstance(): bool
{
return self::$instance instanceof static;
}
public function __construct(
string $host,
?int $port = null,
?int $database = null,
?string $password = null,
string $prefix = ''
) {
if (self::hasInstance()) {
throw new UnexpectedValueException('Only one instance of Cache may exist.');
}
self::$instance = $this;
$this->redis = new Redis;
$this->redis->connect($host, $port);
if ($password !== null && !$this->redis->auth($password)) {
throw new InvalidArgumentException('Redis auth failed.');
}
if ($database !== null && !$this->redis->select($database)) {
throw new UnexpectedValueException('Redis select failed.');
}
$this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$this->redis->setOption(Redis::OPT_PREFIX, $prefix);
}
public function __destruct()
{
$this->redis->close();
self::$instance = null;
}
public function set(string $key, $value, int $ttl = 0)
{
if (is_callable($value)) {
$value = $value();
}
if ($ttl < 0) {
return $value;
} elseif ($ttl < 1) {
$this->redis->set($key, $value);
} else {
$this->redis->setEx($key, $ttl, $value);
}
return $value;
}
public function exists(string $key): bool
{
return $this->redis->exists($key);
}
public function delete($keys): int
{
return $this->redis->delete($keys);
}
public function increment(string $key, int $amount = 1): int
{
if ($amount <= 1) {
return $this->redis->incr($key);
}
return $this->redis->incrBy($key, $amount);
}
public function decrement(string $key, int $amount = 1): int
{
if ($amount <= 1) {
return $this->redis->decr($key);
}
return $this->redis->decrBy($key, $amount);
}
public function get(string $key, $fallback, int $ttl = 0)
{
if ($ttl < 0) {
return is_callable($fallback) ? $fallback() : $fallback;
}
if (!$this->exists($key)) {
return $this->set($key, $fallback, $ttl);
}
return $this->redis->get($key);
}
}

View file

@ -3,7 +3,9 @@ namespace Misuzu;
use Misuzu\Config\ConfigManager;
use PDO;
use PDOStatement;
use InvalidArgumentException;
use UnexpectedValueException;
final class Database
{
@ -48,7 +50,7 @@ final class Database
public static function getInstance(): Database
{
if (!self::hasInstance()) {
throw new \UnexpectedValueException('No instance of Database exists yet.');
throw new UnexpectedValueException('No instance of Database exists yet.');
}
return self::$instance;
@ -63,8 +65,8 @@ final class Database
ConfigManager $config,
string $default = 'default'
) {
if (self::$instance instanceof static) {
throw new \UnexpectedValueException('Only one instance of Database may exist.');
if (self::hasInstance()) {
throw new UnexpectedValueException('Only one instance of Database may exist.');
}
self::$instance = $this;
@ -77,6 +79,26 @@ final class Database
return self::getInstance()->getConnection($name);
}
public static function prepare(string $statement, ?string $connection = null, $options = []): PDOStatement
{
return self::connection($connection)->prepare($statement, $options);
}
public static function query(string $statement, ?string $connection = null): PDOStatement
{
return self::connection($connection)->query($statement);
}
public static function exec(string $statement, ?string $connection = null)
{
return self::connection($connection)->exec($statement);
}
public static function queryCount(?string $connection = null): int
{
return (int)Database::query('SHOW SESSION STATUS LIKE "Questions"', $connection)->fetch()['Value'];
}
public function getConnection(?string $name = null): PDO
{
$name = $name ?? $this->default;

View file

@ -167,6 +167,10 @@ class TemplateEngine
*/
public function render(string $path, ?array $vars = null): string
{
if ($this->twig->isDebug()) {
$this->var('query_count', Database::queryCount());
}
$path = self::fixPath($path);
if ($vars !== null) {

View file

@ -67,6 +67,9 @@
''|date('Y') }} /
{{ ('https://github.com/flashwave/misuzu/tree/' ~ git_branch())|html_link(git_branch(), 'footer__link')|raw }}
# {{ ('https://github.com/flashwave/misuzu/commit/' ~ git_commit_hash(true))|html_link(git_commit_hash(), 'footer__link')|raw }}
{% if query_count is defined %}
/ SQL Queries: {{ query_count|number_format }}
{% endif %}
</footer>
</div>
<script src="/js/libraries.js" charset="utf-8"></script>

View file

@ -70,6 +70,9 @@
''|date('Y') }} /
{{ ('https://github.com/flashwave/misuzu/tree/' ~ git_branch())|html_link(git_branch(), 'footer__copyright__link') }}
# {{ ('https://github.com/flashwave/misuzu/commit/' ~ git_commit_hash(true))|html_link(git_commit_hash(), 'footer__copyright__link') }}
{% if query_count is defined %}
/ SQL Queries: {{ query_count|number_format }}
{% endif %}
</div>
<div class="footer__links">