I use file_get_contents
to grab a remote pricing (updated daily), use substr
to keep only the portions I want (stripping out the currency symbols and other data from the output and only keeping the numbers) and use file_put_contents
to store it into a cache directory which I refer to later.
This is what I have now:-
<?php
$cacheDirectory = $_SERVER['DOCUMENT_ROOT'] . '/cache/';
// Small Plan - US
$cachefile_SM_US = $cacheDirectory . 'SM_US.cache';
if(file_exists($cachefile_SM_US)) {
if(time() - filemtime($cachefile_SM_US) > 1600) {
// too old , re-fetch
$cache_SM_US = file_get_contents('https://remotedomain.com/?get=price&product=10¤cy=1');
$substr_SM_US = substr($cache_SM_US,17,2);
file_put_contents($cachefile_SM_US, $substr_SM_US);
} else {
// cache is still fresh
}
} else {
// no cache, create one
$cache_SM_US = file_get_contents('https://remotedomain.com/?get=price&product=10¤cy=1');
$substr_SM_US = substr($cache_SM_US,17,2);
file_put_contents($cachefile_SM_US, $substr_SM_US);
}
// Large Plan - US
$cachefile_LG_US = $cacheDirectory . 'LG_US.cache';
if(file_exists($cachefile_LG_US)) {
if(time() - filemtime($cachefile_LG_US) > 1600) {
// too old , re-fetch
$cache_LG_US = file_get_contents('https://remotedomain.com/?get=price&product=20¤cy=1');
$substr_LG_US = substr($cache_LG_US,17,2);
file_put_contents($cachefile_LG_US, $substr_LG_US);
} else {
// cache is still fresh
}
} else {
// no cache, create one
$cache_LG_US = file_get_contents('https://remotedomain.com/?get=price&product=20¤cy=1');
$substr_LG_US = substr($cache_LG_US,17,2);
file_put_contents($cachefile_LG_US, $substr_LG_US);
}
// Small Plan - EU
$cachefile_SM_EU = $cacheDirectory . 'SM_EU.cache';
if(file_exists($cachefile_SM_EU)) {
if(time() - filemtime($cachefile_SM_EU) > 1600) {
// too old , re-fetch
$cache_SM_EU = file_get_contents('https://remotedomain.com/?get=price&product=10¤cy=2');
$substr_SM_EU = substr($cache_SM_EU,17,2);
file_put_contents($cachefile_SM_EU, $substr_SM_EU);
} else {
// cache is still fresh
}
} else {
// no cache, create one
$cache_SM_EU = file_get_contents('https://remotedomain.com/?get=price&product=10¤cy=2');
$substr_SM_EU = substr($cache_SM_EU,17,2);
file_put_contents($cachefile_SM_EU, $substr_SM_EU);
}
// Large Plan - EU
$cachefile_LG_EU = $cacheDirectory . 'LG_EU.cache';
if(file_exists($cachefile_LG_EU)) {
if(time() - filemtime($cachefile_LG_EU) > 1600) {
// too old , re-fetch
$cache_LG_EU = file_get_contents('https://remotedomain.com/?get=price&product=20¤cy=2');
$substr_LG_EU = substr($cache_LG_EU,17,2);
file_put_contents($cachefile_LG_EU, $substr_LG_EU);
} else {
// cache is still fresh
}
} else {
// no cache, create one
$cache_LG_EU = file_get_contents('https://remotedomain.com/?get=price&product=20¤cy=2');
$substr_LG_EU = substr($cache_LG_EU,17,2);
file_put_contents($cachefile_LG_EU, $substr_LG_EU);
}
?>
This manual way works when there are only two products (10
and 20
) and two currencies (1
and 2
) as I only need to do it 4 times to get all the pricing I need.
However, I am going to significantly expand the number of products to at least 12 products and 9 currencies so it is not realistic to do them manually.
I believe this can be done more efficiently with PHP foreach loop but I tried a few days and didn't manage to get it to work, maybe because of my weaker understanding of the concept.
I managed to split it up into this:-
<?php
$cacheDirectory = $_SERVER['DOCUMENT_ROOT'] . '/cache/';
$url = 'https://remotedomain.com/?get=price';
$productA = 10;
$productB = 20;
$USD = 1;
$EUR = 2;
// Small Plan - US
$cachefile_SM_US = $cacheDirectory . 'SM_US.cache';
if(file_exists($cachefile_SM_US)) {
if(time() - filemtime($cachefile_SM_US) > 1600) {
// too old , re-fetch
$cache_SM_US = file_get_contents($url . '&product=' . $productA . '¤cy=' . $USD);
$substr_SM_US = substr($cache_SM_US,17,2);
file_put_contents($cachefile_SM_US, $substr_SM_US);
} else {
// cache is still fresh
}
} else {
// no cache, create one
$cache_SM_US = file_get_contents($url . '&product=' . $productA . '¤cy=' . $USD);
$substr_SM_US = substr($cache_SM_US,17,2);
file_put_contents($cachefile_SM_US, $substr_SM_US);
}
// Large Plan - US
$cachefile_LG_US = $cacheDirectory . 'LG_US.cache';
if(file_exists($cachefile_LG_US)) {
if(time() - filemtime($cachefile_LG_US) > 1600) {
// too old , re-fetch
$cache_LG_US = file_get_contents($url . '&product=' . $productB . '¤cy=' . $USD);
$substr_LG_US = substr($cache_LG_US,17,2);
file_put_contents($cachefile_LG_US, $substr_LG_US);
} else {
// cache is still fresh
}
} else {
// no cache, create one
$cache_LG_US = file_get_contents($url . '&product=' . $productB . '¤cy=' . $USD);
$substr_LG_US = substr($cache_LG_US,17,2);
file_put_contents($cachefile_LG_US, $substr_LG_US);
}
// Small Plan - EU
$cachefile_SM_EU = $cacheDirectory . 'SM_EU.cache';
if(file_exists($cachefile_SM_EU)) {
if(time() - filemtime($cachefile_SM_EU) > 1600) {
// too old , re-fetch
$cache_SM_EU = file_get_contents($url . '&product=' . $productA . '¤cy=' . $EUR);
$substr_SM_EU = substr($cache_SM_EU,17,2);
file_put_contents($cachefile_SM_EU, $substr_SM_EU);
} else {
// cache is still fresh
}
} else {
// no cache, create one
$cache_SM_EU = file_get_contents($url . '&product=' . $productA . '¤cy=' . $EUR);
$substr_SM_EU = substr($cache_SM_EU,17,2);
file_put_contents($cachefile_SM_EU, $substr_SM_EU);
}
// Large Plan - EU
$cachefile_LG_EU = $cacheDirectory . 'LG_EU.cache';
if(file_exists($cachefile_LG_EU)) {
if(time() - filemtime($cachefile_LG_EU) > 1600) {
// too old , re-fetch
$cache_LG_EU = file_get_contents($url . '&product=' . $productB . '¤cy=' . $EUR);
$substr_LG_EU = substr($cache_LG_EU,17,2);
file_put_contents($cachefile_LG_EU, $substr_LG_EU);
} else {
// cache is still fresh
}
} else {
// no cache, create one
$cache_LG_EU = file_get_contents($url . '&product=' . $productB . '¤cy=' . $EUR);
$substr_LG_EU = substr($cache_LG_EU,17,2);
file_put_contents($cachefile_LG_EU, $substr_LG_EU);
}
?>
The challenge I have now is how to turn this into a foreach loop which will cycle through each product and each currencies.
Appreciate pointers in the right direction.
Thank you!
Absolutely. Take a look at this example :)
<?php declare(strict_types=1);
interface CacheNormalizer
{
public function normalize(string $text): string;
}
interface PlanDomainToCache
{
public function buildUrl(Plan $plan): string;
}
final class CachedRemoteSiteManager
{
/** @var int Time To Live Cache */
private $timeToLive;
/** @var CacheNormalizer */
private $cacheNormalizer;
/** @var PlanDomainToCache */
private $planDomainToCache;
public function __construct(
int $timeToLive,
CacheNormalizer $cacheNormalizer,
PlanDomainToCache $planDomainToCache
) {
$this->timeToLive = $timeToLive;
$this->cacheNormalizer = $cacheNormalizer;
$this->planDomainToCache = $planDomainToCache;
}
public function updateIfNecessary(Plan $plan): void
{
if ($this->shouldCreateOrUpdateCache($plan)) {
$this->createOrUpdateCache($plan);
}
}
private function shouldCreateOrUpdateCache(Plan $plan): bool
{
return !file_exists($plan->cacheDirectory())
|| time() - filemtime($plan->cacheDirectory()) > $this->timeToLive;
}
private function createOrUpdateCache(Plan $plan): void
{
$urlToCache = $this->planDomainToCache->buildUrl($plan);
$textToCache = file_get_contents($urlToCache);
file_put_contents(
$plan->cacheDirectory(),
$this->cacheNormalizer->normalize($textToCache)
);
}
}
final class Plan
{
/** @var string */
private $cacheDirectory;
/** @var int */
private $product;
/** @var int */
private $currency;
public function __construct(string $cacheDir, int $product, int $currency)
{
$this->cacheDirectory = $cacheDir;
$this->product = $product;
$this->currency = $currency;
}
public function cacheDirectory(): string
{
return $this->cacheDirectory;
}
public function product(): int
{
return $this->product;
}
public function currency(): int
{
return $this->currency;
}
}
// Usage example:
$cacheDirectory = $_SERVER['DOCUMENT_ROOT'] . '/cache/';
$productA = 10;
$productB = 20;
$USD = 1;
$EUR = 2;
/** @var Plan[] */
$plansToCache = [
new Plan($cacheDirectory . 'SM_US.cache', $productA, $USD),
new Plan($cacheDirectory . 'LG_US.cache', $productB, $USD),
new Plan($cacheDirectory . 'SM_EU.cache', $productA, $EUR),
new Plan($cacheDirectory . 'LG_EU.cache', $productB, $EUR),
];
$cacheManager = new CachedRemoteSiteManager(
$cacheTtl = 1600,
new class implements CacheNormalizer {
public function normalize(string $text): string
{
return substr($text, 17, 2);
}
},
new class implements PlanDomainToCache {
public function buildUrl(Plan $plan): string
{
return sprintf(
'https://remotedomain.com/?get=price&product=%d¤cy=%d',
$plan->product(),
$plan->currency()
);
}
}
);
foreach ($plansToCache as $plan) {
$cacheManager->updateIfNecessary($plan);
}
As you can see at the bottom, in the "usage example", I extracted all details (almost all of them) so we can easily define:
UPDATED:
If you want to see how could you extract/decouple every detail from the ending code, inverting the dependencies upwards even for the "Persistence" layer: https://gist.github.com/Chemaclass/01d3f42685ff69f6897192202a32014d