Caching stuff.
This commit is contained in:
parent
d52cb3af63
commit
af4ec2ac45
8 changed files with 226 additions and 45 deletions
|
@ -135,6 +135,7 @@ if (PHP_SAPI === 'cli') {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$app->startCache();
|
||||||
$app->startTemplating();
|
$app->startTemplating();
|
||||||
$tpl = $app->getTemplating();
|
$tpl = $app->getTemplating();
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
use Misuzu\Cache;
|
||||||
use Misuzu\Database;
|
use Misuzu\Database;
|
||||||
|
|
||||||
require_once __DIR__ . '/../misuzu.php';
|
require_once __DIR__ . '/../misuzu.php';
|
||||||
|
|
||||||
$config = $app->getConfig();
|
$config = $app->getConfig();
|
||||||
$tpl = $app->getTemplating();
|
$tpl = $app->getTemplating();
|
||||||
$db = Database::connection();
|
|
||||||
|
|
||||||
if ($config->get('Site', 'embed_linked_data', 'bool', false)) {
|
if ($config->get('Site', 'embed_linked_data', 'bool', false)) {
|
||||||
$tpl->vars([
|
$tpl->vars([
|
||||||
|
@ -17,7 +17,7 @@ if ($config->get('Site', 'embed_linked_data', 'bool', false)) {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$featuredNews = $db->query('
|
$news = Database::query('
|
||||||
SELECT
|
SELECT
|
||||||
p.`post_id`, p.`post_title`, p.`post_text`, p.`created_at`,
|
p.`post_id`, p.`post_title`, p.`post_text`, p.`created_at`,
|
||||||
u.`user_id`, u.`username`,
|
u.`user_id`, u.`username`,
|
||||||
|
@ -32,46 +32,49 @@ $featuredNews = $db->query('
|
||||||
LIMIT 3
|
LIMIT 3
|
||||||
')->fetchAll(PDO::FETCH_ASSOC);
|
')->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$usersCount = (int)$db->query('
|
$statistics = Cache::instance()->get('index:stats:v1', function () {
|
||||||
SELECT COUNT(`user_id`)
|
return [
|
||||||
FROM `msz_users`
|
'users' => (int)Database::query('
|
||||||
')->fetchColumn();
|
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('
|
$changelog = Cache::instance()->get('index:changelog:v1', function () {
|
||||||
SELECT
|
return Database::query('
|
||||||
u.`user_id`, u.`username`, u.`created_at`,
|
SELECT
|
||||||
COALESCE(r.`role_colour`, CAST(0x40000000 AS UNSIGNED)) as `user_colour`
|
c.`change_id`, c.`change_log`,
|
||||||
FROM `msz_users` as u
|
a.`action_name`, a.`action_colour`, a.`action_class`,
|
||||||
LEFT JOIN `msz_roles` as r
|
DATE(`change_created`) as `change_date`,
|
||||||
ON r.`role_id` = u.`display_role`
|
!ISNULL(c.`change_text`) as `change_has_text`
|
||||||
ORDER BY u.`user_id` DESC
|
FROM `msz_changelog_changes` as c
|
||||||
LIMIT 1
|
LEFT JOIN `msz_changelog_actions` as a
|
||||||
')->fetch(PDO::FETCH_ASSOC);
|
ON a.`action_id` = c.`action_id`
|
||||||
|
WHERE DATE(c.`change_created`) >= (
|
||||||
$featuredChangelog = $db->query('
|
SELECT DATE(`change_created`)
|
||||||
SELECT
|
FROM `msz_changelog_changes`
|
||||||
c.`change_id`, c.`change_log`,
|
GROUP BY DATE(`change_created`)
|
||||||
a.`action_name`, a.`action_colour`, a.`action_class`,
|
ORDER BY `change_created` DESC
|
||||||
DATE(`change_created`) as `change_date`,
|
LIMIT 2, 1
|
||||||
!ISNULL(c.`change_text`) as `change_has_text`
|
)
|
||||||
FROM `msz_changelog_changes` as c
|
ORDER BY c.`change_created` DESC
|
||||||
LEFT JOIN `msz_changelog_actions` as a
|
')->fetchAll(PDO::FETCH_ASSOC);
|
||||||
ON a.`action_id` = c.`action_id`
|
}, 1800);
|
||||||
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']);
|
|
||||||
|
|
||||||
echo $tpl->render('home.index', [
|
echo $tpl->render('home.index', [
|
||||||
'users_count' => $usersCount,
|
'users_count' => $statistics['users'],
|
||||||
'last_user' => $lastUser,
|
'last_user' => $statistics['lastUser'],
|
||||||
'featured_changelog' => $featuredChangelog,
|
'featured_changelog' => $changelog,
|
||||||
'featured_news' => $featuredNews,
|
'featured_news' => $news,
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -217,12 +217,30 @@ class Application extends ApplicationBase
|
||||||
public function startDatabase(): void
|
public function startDatabase(): void
|
||||||
{
|
{
|
||||||
if (Database::hasInstance()) {
|
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]);
|
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.
|
* Sets up the templating engine module.
|
||||||
*/
|
*/
|
||||||
|
|
127
src/Cache.php
Normal file
127
src/Cache.php
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,9 @@ namespace Misuzu;
|
||||||
|
|
||||||
use Misuzu\Config\ConfigManager;
|
use Misuzu\Config\ConfigManager;
|
||||||
use PDO;
|
use PDO;
|
||||||
|
use PDOStatement;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use UnexpectedValueException;
|
||||||
|
|
||||||
final class Database
|
final class Database
|
||||||
{
|
{
|
||||||
|
@ -48,7 +50,7 @@ final class Database
|
||||||
public static function getInstance(): Database
|
public static function getInstance(): Database
|
||||||
{
|
{
|
||||||
if (!self::hasInstance()) {
|
if (!self::hasInstance()) {
|
||||||
throw new \UnexpectedValueException('No instance of Database exists yet.');
|
throw new UnexpectedValueException('No instance of Database exists yet.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
|
@ -63,8 +65,8 @@ final class Database
|
||||||
ConfigManager $config,
|
ConfigManager $config,
|
||||||
string $default = 'default'
|
string $default = 'default'
|
||||||
) {
|
) {
|
||||||
if (self::$instance instanceof static) {
|
if (self::hasInstance()) {
|
||||||
throw new \UnexpectedValueException('Only one instance of Database may exist.');
|
throw new UnexpectedValueException('Only one instance of Database may exist.');
|
||||||
}
|
}
|
||||||
|
|
||||||
self::$instance = $this;
|
self::$instance = $this;
|
||||||
|
@ -77,6 +79,26 @@ final class Database
|
||||||
return self::getInstance()->getConnection($name);
|
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
|
public function getConnection(?string $name = null): PDO
|
||||||
{
|
{
|
||||||
$name = $name ?? $this->default;
|
$name = $name ?? $this->default;
|
||||||
|
|
|
@ -167,6 +167,10 @@ class TemplateEngine
|
||||||
*/
|
*/
|
||||||
public function render(string $path, ?array $vars = null): string
|
public function render(string $path, ?array $vars = null): string
|
||||||
{
|
{
|
||||||
|
if ($this->twig->isDebug()) {
|
||||||
|
$this->var('query_count', Database::queryCount());
|
||||||
|
}
|
||||||
|
|
||||||
$path = self::fixPath($path);
|
$path = self::fixPath($path);
|
||||||
|
|
||||||
if ($vars !== null) {
|
if ($vars !== null) {
|
||||||
|
|
|
@ -67,6 +67,9 @@
|
||||||
''|date('Y') }} /
|
''|date('Y') }} /
|
||||||
{{ ('https://github.com/flashwave/misuzu/tree/' ~ git_branch())|html_link(git_branch(), 'footer__link')|raw }}
|
{{ ('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 }}
|
# {{ ('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>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
<script src="/js/libraries.js" charset="utf-8"></script>
|
<script src="/js/libraries.js" charset="utf-8"></script>
|
||||||
|
|
|
@ -70,6 +70,9 @@
|
||||||
''|date('Y') }} /
|
''|date('Y') }} /
|
||||||
{{ ('https://github.com/flashwave/misuzu/tree/' ~ git_branch())|html_link(git_branch(), 'footer__copyright__link') }}
|
{{ ('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') }}
|
# {{ ('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>
|
||||||
|
|
||||||
<div class="footer__links">
|
<div class="footer__links">
|
||||||
|
|
Loading…
Add table
Reference in a new issue