Skip to content

Commit

Permalink
Add and use Cacheable feature
Browse files Browse the repository at this point in the history
  • Loading branch information
trasher committed Feb 18, 2024
1 parent b721549 commit da5509b
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 75 deletions.
162 changes: 162 additions & 0 deletions galette/lib/Galette/Features/Cacheable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?php

/**
* Copyright © 2003-2024 The Galette Team
*
* This file is part of Galette (https://galette.eu).
*
* Galette is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Galette is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Galette. If not, see <http://www.gnu.org/licenses/>.
*/

namespace Galette\Features;

use Analog\Analog;
use Galette\Core\Galette;
use Throwable;

/**
* Cacheable objects trait
*
* @author Johan Cwiklinski <johan@x-tnd.be>
*/

trait Cacheable
{
//number of hours until cache will be invalid
protected int $cache_timeout = 24;

/**
* Handle cache
*
* @param boolean $nocache Do not try to cache
*
* @return void
*/
protected function handleCache(bool $nocache = false): void
{
if ($nocache === false && !Galette::isDebugEnabled()) {
if (!$this->checkCache()) {
$this->makeCache();
} else {
$this->loadCache();
}
}
}

/**
* Check if cache is valid
*
* @return boolean
*/
private function checkCache(): bool
{
$cfile = GALETTE_CACHE_DIR . $this->getCacheFilename();
if (file_exists($cfile)) {
try {
$dformat = 'Y-m-d H:i:s';
$mdate = \DateTime::createFromFormat(
$dformat,
date(
$dformat,
filemtime($cfile)
)
);
$expire = $mdate->add(
new \DateInterval('PT' . $this->cache_timeout . 'H')
);
$now = new \DateTime();
$has_expired = $now > $expire;
return !$has_expired;
} catch (Throwable $e) {
Analog::log(
'Unable check cache expiry. Are you sure you have ' .
'properly configured PHP timezone settings on your server?',
Analog::WARNING
);
return false;
}
} else {
return false;
}
}

/**
* Complete path to cache file
*
* @return string
*/
abstract protected function getCacheFilename(): string;

/**
* Ensure data to cache are present
*
* @return void
*/
abstract protected function prepareForCache(): void;

/**
* Creates/update the cache
*
* @return void
*/
protected function makeCache(): void
{
$this->prepareForCache();
$cfile = $this->getCacheFilename();
$cdir = dirname($cfile);
if (!file_exists($cdir)) {
mkdir($cdir, 0755, true);
}
$stream = fopen($cfile, 'w+');
fwrite(
$stream,
$this->getDataTocache()
);
fclose($stream);
}

/**
* Get data to cache
*
* @return string
*/
protected function getDataTocache(): string
{
throw new \RuntimeException('Method not implemented');
}

/**
* Loads entries from cache
*
* @return void
*/
protected function loadCache(): void
{
$cfile = $this->getCacheFilename();
$fcontents = file_get_contents($cfile);

if (!$this->cacheLoaded($fcontents)) {
$this->makeCache();
}
}

/**
* Called once cache has been loaded.
*
* @param mixed $content Content from cache
*
* @return bool
*/
abstract protected function cacheLoaded($content): bool;
}
103 changes: 31 additions & 72 deletions galette/lib/Galette/IO/News.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
namespace Galette\IO;

use Galette\Core\Galette;
use Galette\Features\Cacheable;
use Throwable;
use Analog\Analog;

Expand All @@ -32,10 +33,10 @@
*/
class News
{
private string $cache_filename = '%feed.cache';
use Cacheable;

protected string $cache_filename = '%feed.cache';
private int $show = 10;
//number of hours until cache will be invalid
private int $cache_timeout = 24;
private ?string $feed_url = null;
/** @var array<int, array<string, string>> */
private array $posts = [];
Expand All @@ -58,106 +59,55 @@ public function __construct(string $url, bool $nocache = false)

//only if cache should be used
if ($nocache === false && !Galette::isDebugEnabled()) {
if (!$this->checkCache()) {
$this->makeCache();
} else {
$this->loadCache();
}
$this->handleCache($nocache);
} else {
$this->parseFeed();
}
}

/**
* Check if cache is valid
*
* @return boolean
*/
private function checkCache(): bool
{
$cfile = $this->getCacheFilename();
if (file_exists($cfile)) {
try {
$dformat = 'Y-m-d H:i:s';
$mdate = \DateTime::createFromFormat(
$dformat,
date(
$dformat,
filemtime($cfile)
)
);
$expire = $mdate->add(
new \DateInterval('PT' . $this->cache_timeout . 'H')
);
$now = new \DateTime();
$has_expired = $now > $expire;
return !$has_expired;
} catch (Throwable $e) {
Analog::log(
'Unable check cache expiry. Are you sure you have ' .
'properly configured PHP timezone settings on your server?',
Analog::WARNING
);
return false;
}
} else {
return false;
}
}

/**
* Creates/update the cache
* Get data to cache
*
* @return void
* @return string
*/
private function makeCache(): void
protected function getDataTocache(): string
{
$this->parseFeed();
$cfile = $this->getCacheFilename();
$stream = fopen($cfile, 'w+');
fwrite(
$stream,
Galette::jsonEncode(
$this->posts
)
return Galette::jsonEncode(
$this->posts
);
fclose($stream);
}

/**
* Loads entries from cache
* Called once cache has been loaded.
*
* @return void
* @param mixed $contents Content from cache
*
* @return bool
*/
private function loadCache(): void
protected function cacheLoaded($contents): bool
{
$refresh_cache = false;
$cfile = $this->getCacheFilename();
$fcontents = file_get_contents($cfile);
if (Galette::isSerialized($fcontents)) {
if (Galette::isSerialized($contents)) {
//legacy cache format
$this->posts = unserialize($fcontents);
$this->posts = unserialize($contents);
} else {
$this->posts = Galette::jsonDecode($fcontents);
$this->posts = Galette::jsonDecode($contents);
}

//check if posts were cached
if (count($this->posts) == 0) {
$this->parseFeed();
$refresh_cache = true;
return false;
}

if ($refresh_cache === true) {
$this->makeCache();
}
return true;
}

/**
* Complete path to cache file
*
* @return string
*/
private function getCacheFilename(): string
protected function getCacheFilename(): string
{
return GALETTE_CACHE_DIR . str_replace(
'%feed',
Expand Down Expand Up @@ -232,7 +182,6 @@ private function parseFeed(): void
}
}


/**
* Get posts
*
Expand Down Expand Up @@ -291,4 +240,14 @@ protected function allowURLFOpen(): bool
{
return ini_get('allow_url_fopen');
}

/**
* Ensure data to cache are present
*
* @return void
*/
protected function prepareForCache(): void
{
$this->parseFeed();
}
}

0 comments on commit da5509b

Please sign in to comment.