Kcko
4/2/2020 - 9:08 PM

11. Proxy

<?php

include "1.php";


/*

    Definice
    --------
    Návrhový vzor Proxy kontroluje přístup k objektu pomocí zástupce, který se používá
    místo vlastního objektu.

    Pro implementaci zástupce typu Protection Proxy je nutné provést následující
    kroky:
    1. Vytvořit třídu, která implementuje veškerá rozhraní implementované třídou,
    jejíž instance mají být chráněné.
    2. Ve všech metodách delegovat volání na objekt, který provede požadovanou
    úlohu.
    3. Vytvořit potomka třídy z bodu 2 a v relevantních metodách implementovat
    kontrolní mechanizmy.

*/


abstract class PublicationProxy implements Publication
{
    protected $publication;

    public function __construct(Publication $publication)
    {
        $this->publication = $publication;
    }

    public function open()
    {
        return $this->publication->open();
    }

    public function close()
    {
        return $this->publication->close();
    }

    public function setPageNumber($page)
    {
        return $this->publication->setPageNumber($page);
    }

    public function getPageNumber()
    {
        return $this->publication->getPageNumber();
    }

    public function getDailyRate($days = 1)
    {
        return $this->publication->getDailyRate($days);
    }

    public function getCategory()
    {
        return $this->publication->getCategory();
    }

    public function getPageCount()
    {
        return $this->publication->getPageCount();
    }
}


class PrepaidPublicationProxy extends PublicationProxy
{
    protected $startPage;
    protected $endPage;

    public function __construct(Publication $publication, $startPage, $endPage)
    {
        parent::__construct($publication);
        $this->startPage = $startPage;

        $this->endPage = $endPage;
    }

    public function setPageNumber($page)
    {
        if ($this->startPage > $page || $this->endPage < $page) {
            throw new OutOfRangeException(
                $page,
                $this->startPage,
                $this->endPage
            );
        }
        return $this->publication->setPageNumber($page);
    }
}


class OutOfRangeException extends \Exception
{
    protected $page;
    protected $startPage;
    protected $endPage;
    public function __construct($page, $startPage, $endPage)
    {
        $this->page = $page;
        $this->startPage = $startPage;
        $this->endPage = $endPage;
        $this->message = sprintf(
            "Požadovaná strana číslo %dse nenachází v předplaceném rozsahu stran %d - %d.",
            $this->page,
            $this->startPage,
            $this->endPage
        );
    }

    public function getPage()
    {
        return $this->page;
    }

    public function getStartPage()
    {
        return $this->startPage;
    }

    public function getEndPage()
    {
        return $this->endPage;
    }
}


$book = new Book('medicína', 650);
$proxy = new PrepaidPublicationProxy($book, 261, 414);
$proxy->open();

try 
{
    $proxy->setPageNumber(300);
    print "Kniha je otevřená na straně 300.\n";
    $proxy->setPageNumber(115);
    print "Kniha je otevřená na straně 115.\n";
} 
catch (OutOfRangeException $e) {
    print $e->getMessage() . "\n";
}
$proxy->close();

/*
    Kniha je otevřená na straně 300.
    Požadovaná strana číslo 115 se nenachází
    v předplaceném rozsahu stran 261-414.
*/