Kcko
3/19/2020 - 9:07 AM

14. Proxy

<?php

interface Downloader
{
    public function download(string $url): string;
}


class SimpleDownloader implements Downloader
{
    public function download(string $url): string
    {
        echo "Downloading a file from the Internet.\n";
        $result = file_get_contents($url);
        echo "Downloaded bytes: " . strlen($result) . "\n";
        
        return $result;
    }
}


class CachingDownloader implements Downloader
{
    /**
     * @var SimpleDownloader
     */
    private $downloader;

    /**
     * @var string[]
     */
    private $cache = [];

    public function __construct(SimpleDownloader $downloader)
    {
        $this->downloader = $downloader;
    }

    public function download(string $url): string
    {
        if (!isset($this->cache[$url])) {
            echo "CacheProxy MISS. ";
            $result = $this->downloader->download($url);
            $this->cache[$url] = $result;
        } else {
            echo "CacheProxy HIT. Retrieving result from cache.\n";
        }
        return $this->cache[$url];
    }
}

// USAGE
$simpleDownload = new SimpleDownloader;
$simpleDownload->download("http://example.com/");

$proxy = new CachingDownloader($simpleDownload);
$proxy->download("http://example.com/");
<?php

interface BankAccount
{
    public function deposit(int $amount);

    public function getBalance(): int;
}


class HeavyBankAccount implements BankAccount
{
    /**
     * @var int[]
     */
    private array $transactions = [];

    public function deposit(int $amount)
    {
        $this->transactions[] = $amount;
    }

    public function getBalance(): int
    {
        // this is the heavy part, imagine all the transactions even from
        // years and decades ago must be fetched from a database or web service
        // and the balance must be calculated from it

        return (int) array_sum($this->transactions);
    }
}


class BankAccountProxy extends HeavyBankAccount implements BankAccount
{
    private ?int $balance = null;

    public function getBalance(): int
    {
        // because calculating balance is so expensive,
        // the usage of BankAccount::getBalance() is delayed until it really is needed
        // and will not be calculated again for this instance

        if ($this->balance === null) {
            $this->balance = parent::getBalance();
        }

        return $this->balance;
    }
}
    
  
// USAGE
$bankAccount = new BankAccountProxy();
$bankAccount->deposit(30); 
echo $bankAccount->getBalance(); // 30
$bankAccount->deposit(120);
echo $bankAccount->getBalance(); // still 30, because cached due to proxy
<?php

interface File {
    public function add (string $name, string $path): void;

    public function get (string $name): void;

    public function remove (string $name): void;
}


class FileProvider implements File {

    public function add (string $name, string $path): void {
        echo "File {$name} from {$path} was added to storage" . PHP_EOL;
    }

    public function get (string $name): void {
        echo "File {$name} was downloaded from storage" . PHP_EOL;
    }

    public function remove (string $name): void {
        echo "File {$name} was removed from storage" . PHP_EOL;
    }
}


class AuthFile implements File {

    const ALLOWED_USERS = [
        "AAA",
    ];
    private $file;

    public function __construct (File $file) {
        $this->file = $file;
    }

    public function add (string $name, string $path): void {
        if ($this->loggedIn()) {
            $this->file->add($name, $path);
        }
    }

    public function get (string $name): void {
        if ($this->loggedIn()) {
            $this->file->get($name);
        }
    }

    public function remove (string $name): void {
        if ($this->loggedIn()) {
            $this->file->remove($name);
        }
    }

    private function loggedIn () {
        if (isset($_SESSION["username"]) && in_array($_SESSION["username"], self::ALLOWED_USERS)) {
            echo "User can perform action" . PHP_EOL;

            return true;
        } else {
            echo "User can not perform action" . PHP_EOL;

            return false;
        }
    }
}


class User {

    public function login ($name) {
        echo "Logging in as {$name}" . PHP_EOL;
        $_SESSION["username"] = $name;
    }

    public function logOut () {
        echo "Logging out" . PHP_EOL;
        unset($_SESSION["username"]);
    }

}



session_start();

$provider = new FileProvider();
$fileAuth = new AuthFile($provider);

$fileAuth->add("test-file.png", "/home/ubuntu");
$fileAuth->remove("test-file.png");
$fileAuth->get("test-file.png");

$auth = new User();
$auth->login("AAA");

$fileAuth->add("test-file.png", "/home/ubuntu");
$fileAuth->remove("test-file.png");
$fileAuth->get("test-file.png");

$auth->logOut();
$auth->login("BBB");

$fileAuth->add("test-file.png", "/home/ubuntu");
$fileAuth->remove("test-file.png");
$fileAuth->get("test-file.png");
session_destroy();


/*

File test-file.png from /home/ubuntu was added to storage
File test-file.png was removed from storage
File test-file.png was downloaded from storage
Logging in as AAA
User can perform action
File test-file.png from /home/ubuntu was added to storage
User can perform action
File test-file.png was removed from storage
User can perform action
File test-file.png was downloaded from storage
Logging out
Logging in as BBB
User can not perform action
User can not perform action
User can not perform action

*/
<?php

abstract class ReadFileAbstract
{
    protected $fileName;
    protected $contents;
 
    public function getFileName()
    {
        return $this->fileName;
    }
 
    public function setFileName($fileName)
    {
        $this->fileName = $fileName;
    }
 
    public function getContents()
    {
        return $this->contents;
    }
}


lass ReadFile extends ReadFileAbstract
{
    const DOCUMENTS_PATH = "/home/simon";
 
    public function __construct($fileName)
    {
        $this->setFileName($fileName);
        $this->contents = file_get_contents(self::DOCUMENTS_PATH . "/" . $this->fileName);
    }
}
 
 
class ReadFileProxy extends ReadFileAbstract
{
    private $file;
 
    public function __construct($fileName)
    {
        $this->fileName = $fileName;
    }
 
    public function lazyLoad()
    {
        if ($this->file === null) {
            $this->file = new ReadFile($this->fileName);
        }
        return $this->file;
    }
}


// usage
$proxies = array();
 
for ($i = 0; $i < 10; $i++) {
    // tell the proxy which file should be read (when lazy loaded)
    $proxies[$i] = new ReadFileProxy("file" . $i . ".txt");
}
 
// Now it's time to read the contents of file3.txt
$file3 = $proxies[3]->lazyLoad();
 
// echo the contents of file3.txt
echo $file3->getContents();