Skip to content

Instantly share code, notes, and snippets.

@Chemaclass
Last active April 17, 2020 08:10
Show Gist options
  • Select an option

  • Save Chemaclass/01d3f42685ff69f6897192202a32014d to your computer and use it in GitHub Desktop.

Select an option

Save Chemaclass/01d3f42685ff69f6897192202a32014d to your computer and use it in GitHub Desktop.
This is the code that I used to verify locally my answer for a concret stackoverflow question
<?php declare(strict_types=1);
# https://stackoverflow.com/a/61230034/3454593
// Usage example:
$cacheManager = new CachedRemoteSiteManager(
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 "https://remotedomain.com/?get=price&product={$plan->product()}&currency={$plan->currency()}";
}
},
new class implements CachePersistence {
public function shouldCreateOrUpdate(string $path): bool {
return !\file_exists($path) || \time() - \filemtime($path) > 1600;
}
public function getContent(string $path): string {
return \file_get_contents($path);
}
public function write(string $path, string $content): void {
\file_put_contents($path, $content);
}
}
);
$plan = new Plan('cache.dir', $productA = 10, $EUR = 2);
$cacheManager->updateIfNecessary($plan);
// The code:
interface CacheNormalizer {
public function normalize(string $text): string;
}
interface CachePersistence {
public function shouldCreateOrUpdate(string $path): bool;
public function getContent(string $path): string;
public function write(string $path, string $content): void;
}
interface PlanDomainToCache {
public function buildUrl(Plan $plan): string;
}
final class CachedRemoteSiteManager {
private CacheNormalizer $normalizer;
private PlanDomainToCache $planDomainToCache;
private CachePersistence $persistence;
public function __construct(CacheNormalizer $normalizer, PlanDomainToCache $toCache, CachePersistence $persistence) {
$this->normalizer = $normalizer;
$this->planDomainToCache = $toCache;
$this->persistence = $persistence;
}
public function updateIfNecessary(Plan $plan): void {
if ($this->persistence->shouldCreateOrUpdate($plan->cacheDirectory())) {
$this->createOrUpdateCache($plan);
}
}
private function createOrUpdateCache(Plan $plan): void {
$urlToCache = $this->planDomainToCache->buildUrl($plan);
$textToCache = $this->persistence->getContent($urlToCache);
$this->persistence->write($plan->cacheDirectory(), $this->normalizer->normalize($textToCache));
}
}
final class Plan {
private string $cacheDirectory;
private int $product;
private int $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;
}
public function __toString(): string {
return "Plan d:{$this->cacheDirectory},c:{$this->currency},p:{$this->product}";
}
}
// The tests:
use PHPUnit\Framework\TestCase;
final class CachedRemoteSiteManagerTest extends TestCase
{
public function testCacheShouldNotBeCreated(): void {
$persistence = $this->stubCachePersistence($shouldCreateOrUpdate = false);
$cacheManager = new CachedRemoteSiteManager($this->newNormalizer(), $this->newPlanDomainToCache(), $persistence);
$cacheManager->updateIfNecessary(new Plan('cache.dir', $productA = 10, $EUR = 2));
self::assertEmpty($persistence->memoryList());
}
public function testCacheShouldBeCreated(): void {
$persistence = $this->stubCachePersistence($shouldCreateOrUpdate = true);
$cacheManager = new CachedRemoteSiteManager($this->newNormalizer(), $this->newPlanDomainToCache(), $persistence);
$plan = new Plan('cache.dir', $productA = 10, $EUR = 2);
$cacheManager->updateIfNecessary($plan);
self::assertEquals(['cache.dir' => (string) $plan], $persistence->memoryList());
}
private function newNormalizer(): CacheNormalizer {
return new class implements CacheNormalizer {
public function normalize(string $text): string {
return $text;
}
};
}
private function newPlanDomainToCache(): PlanDomainToCache {
return new class implements PlanDomainToCache {
public function buildUrl(Plan $plan): string {
return (string) $plan;
}
};
}
private function stubCachePersistence(bool $shouldCreateOrUpdate): CachePersistence {
return new class ($shouldCreateOrUpdate) implements CachePersistence {
private array $memoryList = [];
private bool $shouldCreateOrUpdate;
public function __construct(bool $shouldCreateOrUpdate) {
$this->shouldCreateOrUpdate = $shouldCreateOrUpdate;
}
public function shouldCreateOrUpdate(string $path): bool {
return $this->shouldCreateOrUpdate;
}
public function getContent(string $path): string {
return $path;
}
public function write(string $path, string $content): void {
$this->memoryList[$path] = $content;
}
public function memoryList(): array {
return $this->memoryList;
}
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment