/ Gists

Gists

On gists

Css Tooltip aka Superkoders (+ my solution wo JS)

CSS HTML

tooltip.html #

<!-- 

https://jsbin.com/fetikedayu/1/edit?html,css,js,output 
https://jsbin.com/zofifoceli/edit?html,css,output
-->

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>JS Bin</title>
      <style>
        .c-tooltip {
    display: inline-block;
    vertical-align: middle;
    margin: -2px 0 0 5px;
    position: relative;
    font-weight: 400;
    height: 16px;
    width: 16px;
    margin: 250px;
    border: 1px solid red;
  
}


.c-tooltip__text {
    display: block;
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    position: absolute;
    left: 50%;
    top: calc(100% + 20px);
    transform: translate3d(-50%,20px,0);
    width: 320px;
    max-width: 80vw;
    padding: 20px 20px 0;
    background-color: #fff;
    color: #000;
    transition: opacity .3s,transform .3s,visibility 0s .3s;
    border-radius: 4px;
    filter: drop-shadow(0 0 1px #d9d6d4) drop-shadow(0 0 1px #d9d6d4) drop-shadow(0 0 1px #d9d6d4) drop-shadow(0 0 20px rgba(0,0,0,.1));
}

.c-tooltip__text:before
{
  position: absolute;
  background: transparent;
  content: "";
  top: -50px;
  height: 100px;
  width: 100%;
  left: 0;
}

.c-tooltip__pointer {
    position: absolute;
    left: 50%;
    top: -7px;
    display: block;
    width: 14px;
    height: 14px;
    transform: translateX(-50%) rotate(45deg);
    background-color: #fff;
}

.c-tooltip--visible .c-tooltip__text,
.c-tooltip:hover .c-tooltip__text,
.c-tooltip__text:hover
{
    visibility: visible;
    opacity: 1;
    pointer-events: all;
    transform: translate3d(-50%,0,0);
    transition: visibility 0s .3s,opacity .3s .3s,transform .3s .3s;
    z-index: 100;
}
        
      </style>
   </head>
   <body>
      <div class="c-tooltip">
         <span class="c-tooltip__icon">
            <svg viewBox="0 0 16 16">
               <path d="M0 8C0 3.584 3.584 0 8 0C12.416 0 16 3.584 16 8C16 12.416 12.416 16 8 16C3.584 16 0 12.416 0 8ZM9.73605 8.13602L10.456 7.40002C10.912 6.94402 11.2 6.30402 11.2 5.60002C11.2 3.83202 9.76805 2.40002 8.00005 2.40002C6.23205 2.40002 4.80005 3.83202 4.80005 5.60002L6.40005 5.60002C6.40005 4.72002 7.12005 4.00002 8.00005 4.00002C8.88005 4.00002 9.60005 4.72002 9.60005 5.60002C9.60005 6.04002 9.42405 6.44002 9.12805 6.72802L8.13605 7.73602C7.56005 8.32002 7.20005 9.12002 7.20005 10L7.20005 10.4L8.80005 10.4C8.80005 9.20002 9.16005 8.72002 9.73605 8.13602ZM8.79995 13.6L7.19995 13.6L7.19995 12L8.79995 12L8.79995 13.6Z"></path>
            </svg>
         </span>
         <div class="c-tooltip__text">
            <span class="c-tooltip__pointer"></span>
            <p><a class="c-tooltip__link" href="https://www.vzhurudolu.cz/prirucka/metrika-lps">LPS (Lighthouse Performance Score)</a> je hlavní skóre nástroje Lighthouse pro tuto konkrétní stránku. LPS měříme každý den syntetickým testem.</p>
            <p>LPS se nepromítá do celkového zhodnocení stránky.</p>
            <p><strong>Optimální hodnota ja 90&nbsp;% a více.</strong></p>
         </div>
      </div>
   </body>
</html>

On gists

PHP DOM - saveHtml (solution without entities and html,body tags)

PHP PHP-PHPDOM

dom.php #

<?php
 
$string = '<div>ěščřžýáíé</div><p>testik</p> <p>testik2</p>';
 
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->loadHTML('<body>'.mb_convert_encoding($string, 'HTML-ENTITIES', 'UTF-8').'</body>');
 
// změny na $dom
 
echo substr($dom->saveHTML($dom->documentElement), 12, -14);

On gists

Update table col by random date / string

MySql MySql tricks MySql - advanced

update.sql #

-- datetime
SET @MIN = '2019-06-29 00:53:27';
SET @MAX = '2019-06-29 13:53:27';

UPDATE tablename
SET columnname = TIMESTAMPADD(SECOND, FLOOR(RAND() * TIMESTAMPDIFF(SECOND, @MIN, @MAX)), @MIN)

-- https://stackoverflow.com/questions/24378490/update-table-with-random-values-from-given-set-of-string-values
-- string
update table t
    set col = elt(floor(rand()*3) + 1, 'value1', 'value2', 'value3');
    
-- or
UPDATE `table`
SET `column`=(CASE CEIL(RAND()*3)
              WHEN 1 THEN 'value1'
              WHEN 2 THEN 'value2'
              WHEN 3 THEN 'value3'
          END);
          
          
-- random numbet between N a M

-- For range (min..max( (min inclusive, max exclusive) it is:
FLOOR( RAND() * (max-min) + min )
 
-- For range (min..max) (min+max inclusive) it is:
FLOOR( RAND() * (max-min+1) + min )

On gists

SQL array - NDB - args

Nette MySql

args.php #

<?php
// DIBI
$q = []
array_push('SELECT * FROM %n', $table);
array_push('WHERE id > %d', $id);

$res = dibi::fetchAll($q);


// NDB
$q = $args = [];
$q[] = "SELECT * FROM ?";
$args[] = $table;

$q[] = "WHERE id > ?";
$args[] = $id;

$res = $this->db->fetchAll(implode(' ', $q), ...$args);



On gists

Mike helpers fns, youtube lazy, inViewport

jQuery

mike-js-helpers.js #


(function($){

	$.fn.isInViewport = function(){
		var elementTop = $(this).offset().top;
		var elementBottom = elementTop + $(this).outerHeight();
		var viewportTop = $(window).scrollTop();
		var viewportBottom = viewportTop + $(window).height();
		return (elementBottom > viewportTop && elementTop < viewportBottom);
	};
	
	$.fn.youTubeImage = function(){
		this.each(function(){
			var src = $(this).find('iframe').attr('title'); //.attr('src')
			var arr = src.split('/');
			
			if(typeof arr[2] != 'undefined'){
				if(arr[2].indexOf('youtube')+1){
					$(this).addClass('is-youtube');
				}
			}
			
			if(arr.length){
				var id = arr[arr.length-1].replace(/^(.*)\?(.*)$/, '$1');
				var image = 'http://img.youtube.com/vi/' + id + '/0.jpg';
				$(this).css({backgroundImage:'url(' + image + ')'});
			}
			
			var href = 'https://www.youtube.com/watch?v=' + id;
			$(this).find('a').attr({ href: href, target: '_blank'});
		});
		
		return this;
	};
	
	$.fn.showWhenScrolled = function(){
		var self = this;
		this.init = function(){
			self.each(function(){
				var frame = $(this).find('iframe');
				if($(this).isInViewport()){
					if(!frame.attr('src')){
						frame.attr({ src : frame.attr('title') });
					}
				}
			});
		};
		
		$(window).on('scroll resize orientationchange', function(){
			self.init();
		});
		
		self.init();
		
		return this;
	};

}(jQuery));

On gists

21. State

Navrhove vzory - Bohmer

state.php #

<?php
// State

/*

Definice
--------
Návrhový vzor State umožňuje objektu změnit chování, změní-li se jeho vnitřní
stav. Navenek se tato změna jeví, jako by objekt změnil svoji třídu.
Pro implementaci tohoto návrhového vzoru jsou nutné následující kroky:
1. V aplikaci identifikovat třídu, jejíž chování závisí na aktuálním stavu in stance.
2. Identifikovat metody odpovědné za změnu stavu a vytvořit rozhraní, které
bude obsahovat tyto metody.
3. Vytvořit způsob pro uložení aktuálního stavu objektu v původní třídě
a vytvořit metodu zabezpečující změnu aktuálního stavu.
4. Vytvořit způsob, kterým bude třída sama schopná spravovat svoje stavy. Případně
je možné spravovat jednotlivé stavy pomocí továrny nebo je implementovat
jako jedináčky.
5. Implementovat jednotlivé třídy stavů a zabezpečit přechody mezi nimi.

*/


// BAD

$printer = new LaserPrinter('Printer 1');
$book = new Book('PC', 580);

$printer->plugIn();
$printer->turnOn();
$printer->warmUp();
$printer->printPublication($book, 5);
$printer->turnOff();
$printer->unPlug();

interface Printer 
{
    public function plugIn();
    public function unPlug();
    public function turnOn();
    public function turnOff();
    public function warmUp();
    public function printPublication(Publication $p, $count = 1);
    public function getType();
    public function getPageCounter();
}

/*

Implementovali jste velmi monolitické bloky kódu. Téměř každá metoda
obsahuje bloky if, které se musejí provádět jeden za druhým.
Takovýto kód není otevřený pro další rozšíření. Přijde-li v budoucnosti
požadavek, že není možné začít tisk, pokud neproběhla vnitřní diagnostika
tiskárny, budete muset kvůli doplnění jedné dodatečné podmínky změnit
několik metod.

*/
class LaserPrinter implements Printer 
{
    protected $plugedIn = false;
    protected $turnedOn = false;
    protected $warmedUp = false;
    protected $type = null;
    protected $pageCounter = 0;

    function __construct($type)
    {
        $this->type = $type;
    }

    public function plugIn()
    {
        $this->plugedIn = true;
        print "Tiskárna zapojena.\n";
    }

    public function turnOn() 
    {
        if (true !== $this->plugedIn) 
        {
            throw new \BadMethodCallException(
            "Tiskárna nebyla zapojena do sítě."
            );
        }

        $this->turnedOn = true;
        print "Tiskárna zapnuta.\n";
    }

    public function warmUp()
    {
        if (true !== $this->plugedIn)
        {
            throw new \BadMethodCallException("Tiskárna nebyla zapojena do sítě.");
        }

        if (true !== $this->turnedOn)
        {
            throw new \BadMethodCallException("Tiskárna nebyla zapnuta.");
        }

        $this->warmedUp = true;
        print "Tiskárna rozehřátá.\n";
    }


    public function printPublication(Publication $p, $count = 1)
    {
        if (true !== $this->plugedIn) {
            throw new \BadMethodCallException(
                "Tiskárna nebyla zapojena do sítě."
            );
        }
        if (true !== $this->turnedOn) {
            throw new \BadMethodCallException("Tiskárna nebyla zapnuta.");
        }
        if (true !== $this->warmedUp) {
            throw new \BadMethodCallException("Tiskárna nebyla rozehřátá.");
        }
        $pageCount = $p->getPageCount();
        $this->pageCounter += $pageCount * $count;
        return true;
    }

    public function turnOff()
    {
        $this->warmedUp = false;
        $this->turnedOn = false;
        print "Tiskárna vypnutá.\n";
    }

    public function unPlug()
    {
        if (true === $this->turnedOn) {
            throw new \BadMethodCallException("Tiskárna je pořád zapnuta.");
        }
        $this->plugedIn = false;
        print "Tiskárna odpojena.\n";
    }

    public function getType()
    {
        return $this->type;
    }
        
    public function getPageCounter() 
    {
        return $this->pageCounter;
    }

}



// GOOD, pattern STATE
interface PrinterState 
{
    const STATE_OFFLINE = 0;
    const STATE_PLUGED_IN = 1;
    const STATE_TURNED_ON = 2;
    const STATE_WARMED_UP = 3;

    public function setState(PrinterState $state);
    public function getState($stateId);
    public function plugIn();
    public function turnOn();
    public function warmUp();
    public function printPublication(Publication $p, $count = 1);
    public function turnOff();
    public function unPlug();
}

class LaserPrinter implements Printer
{
    protected $state;
    protected $states = array();
    protected $type = null;
    protected $pageCounter = 0;

    function __construct($type)
    {
        $this->type = $type;

        $this->states[Printer::STATE_OFFLINE] = new OfflinePrinterState($this);
        $this->states[Printer::STATE_PLUGED_IN] = new PlugedInPrinterState($this);
        $this->states[Printer::STATE_TURNED_ON] = new TurnedOnPrinterState($this);
        $this->states[Printer::STATE_WARMED_UP] = new WarmedUpPrinterState($this);
        $this->state = $this->getState(Printer::STATE_OFFLINE);
    }

    public function plugIn()
    {
        $this->state->plugIn();
    }

    public function turnOn()
    {
        $this->state->turnOn();
    }

    public function warmUp()
    {
        $this->state->warmUp();
    }

    public function printPublication(Publication $p, $count = 1)
    {
        $pageCount = $this->state->printPublication($p, $count);
        if (false !== $pageCount) {
            $this->pageCounter += $pageCount;
        }
    }

    public function turnOff()
    {
        $this->state->turnOff();
    }

    public function unPlug()
    {
        $this->state->unPlug();
    }

    public function getType()
    {
        return $this->type;
    }

    public function getPageCounter()
    {
        return $this->pageCounter;
    }

    public function getState($stateId) 
    {
        return $this->states[$stateId];
    }

    public function setState(PrinterState $state) 
    {
        printf("Tiskárna měni stav: %s.\n", get_class($state));
        $this->state = $state;
    }
}


abstract class AbstractPrinterState implements PrinterState 
{
    protected $printer;

    public function __construct(Printer $printer) 
    {
        $this->printer = $printer;
    }
}

class OfflinePrinterState extends AbstractPrinterState
{
    public function plugIn()
    {
        $this->printer->setState(
            $this->printer->getState(Printer::STATE_PLUGED_IN)
        );
        print "Tiskárna zapojena do sítě.\n";
    }

    public function turnOn()
    {
        throw new \BadMethodCallException("Tiskárna nebyla zapojena.\n");
    }
    public function warmUp()
    {
        throw new \BadMethodCallException("Tiskárna nebyla zapnuta.\n");
    }
    public function printPublication(Publication $p, $count = 1)
    {
        throw new \BadMethodCallException("Není možné.\n");
    }
    public function turnOff()
    {
        throw new \BadMethodCallException("Tiskárna nebyla zapnuta.\n");
    }
    public function unPlug()
    {
        throw new \BadMethodCallException("Tiskárna nebyla zapojena.\n");
    }
}


class PlugedInPrinterState extends AbstractPrinterState
{
    public function plugIn()
    {
        throw new \BadMethodCallException("Tiskárna již byla zapojena.\n");
    }
    public function turnOn()
    {
        $this->printer->setState(
            $this->printer->getState(Printer::STATE_TURNED_ON)
        );
        print "Tiskárna zapnuta.\n";
    }
    public function warmUp()
    {
        throw new \BadMethodCallException("Tiskárna nebyla zapnuta.\n");
    }
    public function printPublication(Publication $p, $count = 1)
    {
        throw new \BadMethodCallException("Není možné.\n");
    }
    public function turnOff()
    {
        throw new \BadMethodCallException("Tiskárna nebyla zapnuta.\n");
    }
    public function unPlug()
    {
        $this->printer->setState(
            $this->printer->getState(Printer::STATE_OFFLINE)
        );
        print "Tiskárna odpojena.\n";
    }
}


class TurnedOnPrinterState extends AbstractPrinterState
{
    public function plugIn()
    {
        throw new \BadMethodCallException("Tiskárna již byla zapojena.\n");
    }

    public function turnOn()
    {
        throw new \BadMethodCallException("Tiskárna již byla zapnuta.\n");
    }
    public function warmUp()
    {
        $this->printer->setState(
            $this->printer->getState(Printer::STATE_WARMED_UP)
        );
        print "Tiskárna rozehřátá.\n";
    }
    public function printPublication(Publication $p, $count = 1)
    {
        throw new \BadMethodCallException("Není možné.\n");
    }
    public function turnOff()
    {
        $this->printer->setState(
            $this->printer->getState(Printer::STATE_PLUGED_IN)
        );
        print "Tiskárna vypnutá.\n";
    }
    public function unPlug()
    {
        throw new \BadMethodCallException("Tiskárna je pořád zapnutá.\n");
    }
}


class WarmedUpPrinterState extends AbstractPrinterState
{
    public function plugIn()
    {
        throw new \BadMethodCallException("Tiskárna již byla zapojena.\n");
    }
    public function turnOn()
    {
        throw new \BadMethodCallException("Tiskárna již byla zapnuta.\n");
    }
    public function warmUp()
    {
        throw new \BadMethodCallException("Tiskárna již byla rozehřáta.\n");
    }
    public function printPublication(Publication $p, $count = 1)
    {
        $pageCount = $p->getPageCount() * $count;
        printf("Vytištěných %d stran.\n", $pageCount);
        return $pageCount;
    }
    public function turnOff()
    {
        $this->printer->setState(
            $this->printer->getState(Printer::STATE_PLUGED_IN)
        );
        print "Tiskárna vypnutá.\n";
    }
    public function unPlug()
    {
        throw new \BadMethodCallException("Tiskárna je pořád zapnutá.\n");
    }
}


// USAGE
$printer = new LaserPrinter('Printer 1');
$book = new Book('PC', 580);

$printer->plugIn();
$printer->turnOn();
$printer->warmUp();
$printer->printPublication($book, 5);
$printer->turnOff();
$printer->unplug();

On gists

22. Strategy

Navrhove vzory - Bohmer

strategy.php #

<?php

/*

Definice
--------
Návrhový vzor Strategy definuje rodinu algoritmů, které zapouzdřuje, a umožňuje
jejich záměnu nezávisle na klientovi, který ji používá.
Pro implementaci tohoto návrhového vzoru jsou nutné následující kroky:¨

1. Definovat rozhraní, která budou muset implementovat všechny třídy z rodiny
algoritmů.
2. Implementovat minimálně 2 konkrétní implementace rozhraní z bodu 1.
3. Vytvořit způsob, kterým bude do objektu využívajícího tento vzor vložena
konkrétní implementace třídy z bodu 2.
4. Ve třídě využívající vzor Strategy vytvořit metodu, která své volání deleguje
na objekt vložený do třídy v bodě 3.

*/


interface Debugger
{
    public function debug($message);
}

class DebuggerEcho implements Debugger
{
    public function debug($message)
    {
        echo $message . PHP_EOL;
    }
}


class DebuggerLog implements Debugger
{
    // zapis do souboru, pro demonstraci jen s prefixem ...
    public function debug($message)
    {
        echo 'LOG: ' . $message . PHP_EOL;
    }
}

class DebuggerNull implements Debugger
{
    public function debug($message)
    {
        
    }
}


// $library = new Library(new DebuggerEcho);

On gists

20. Iterator

Navrhove vzory - Bohmer

iterator.php #

<?php
// Iterator

/*

Definice
--------

Návrhový vzor Iterator umožňuje sekvenčně přistupovat k prvkům složených objektů
bez zveřejnění jejich základní struktury.
Pro využití návrhového vzoru Iterator jsou nutné následující kroky:

1. Zvolit, zda má třída implementovat rozhraní Iterator, nebo rozhraní
IteratorAggregate.
2. Implementovat metody vyžadované zvoleným rozhraním.

*/

include '1.php';

class BookList implements \Iterator 
{
    protected $bookDefinitions = array();
    protected $books = array();
    protected $position = 0;

    public function __construct($csvFile)
    {
        if (!file_exists($csvFile)) 
        {
            throw new IOException();
        }

        $fp = fopen($csvFile, 'r');
        while (false != ($line = fgetcsv($fp, 1024, ';'))) {
            $this->bookDefinitions[] = array(
                'category' => $line[0],
                'pagecount' => $line[1]
            );
        }
    }

    public function getBook($position)
    {
        if ($position > count($this->bookDefinitions)) {
            throw new Exception();
        }
        if (!isset($this->books[$position])) {
            $this->books[$position] = new Book(
                $this->bookDefinitions[$position]['category'],
                $this->bookDefinitions[$position]['pagecount']
            );
        }
        return $this->books[$position];
    }

    public function countBooks()
    {
        return count($this->bookDefinitions);
    }
  
    public function current()
    {
        if (!isset($this->books[$this->position])) {
            $this->books[$this->position] = new Book(
                $this->bookDefinitions[$this->position]['category'],
                $this->bookDefinitions[$this->position]['pagecount']
            );
        }
        return $this->books[$this->position];
    }

    public function key()
    {
        return $this->position;
    }

    public function next()
    {
        $this->position++;
    }

    public function rewind()
    {
        $this->position = 0;
    }

    public function valid()
    {
        if ($this->position < count($this->bookDefinitions)) 
        {
            return true;
        }
        return false;
    }

}


$list = new BookList('ext/books.csv');

// 1
for ($j = 0; $j < $list->countBooks(); $j++) 
{
    $book = $list->getBook($j);
    printf("%d -> %s\n", $j, $book->getCategory());
}

echo PHP_EOL;

// 2
$list->rewind();
while ($list->valid()) 
{
    $position = $list->key();
    $book = $list->current();
    printf("%d -> %s\n", $position, $book->getCategory());
    $list->next();
}

echo PHP_EOL;

// 3
foreach($list as $position => $book) 
{
    printf("%d -> %s\n", $position, $book->getCategory());
}


// 4
class ListHelper 
{
    public static function displayBooks(\Traversable $list) 
    {
        foreach($list as $position => $book) 
        {
            printf("%d -> %s\n", $position, $book->getCategory());
        }
    }
}

echo PHP_EOL;

$list = new BookList('ext/books.csv');
ListHelper::displayBooks($list);


echo PHP_EOL;

// chceme iterator pouzit i na pole
$books = array(
    new Book('PC', '100'),
    new Book('MEDICINA', '400'),
    new Book('AUTO-MOTO', '350'),
);

// takhle to nejde bze to neni Traversable
//ListHelper::displayBooks($books);

// takhle to pujde
ListHelper::displayBooks(new ArrayIterator($books));

On gists

19. Visitor

Navrhove vzory - Bohmer

visitor.php #

<?php
// Visitor

/*
Definice
--------
Návrhový vzor Visitor vám umožní přidat nové operace do struktury objektů bez
změny prvků této struktury. Operace, které se mají v této struktuře provést, jsou
zapouzdřené do nové třídy.
Pro vytvoření a použití návštěvníka i v jiných situacích jsou nutné následující
kroky:

1. Analyzovat, jaké typy prvků, které chcete rozšířit o nové funkce, se nacházejí
ve struktuře objektů.
2. Definovat rozhraní pro objekt návštěvníka s deklaracemi metod visit*()
pro každý typ prvku.
3. Do každé třídy, která se používá ve struktuře objektů, přidat metodu
acceptVisitor(), která přijme objekt implementující rozhraní z bodu 2.
V této metodě zavolat příslušnou metodu visit*() objektu návštěvníka
a předat jí aktuální objekt.
4. Projít všechny objekty, na které odkazuje aktuální objekt (poduzly), a jejich
metodě acceptVisitor()předat objekt návštěvníka.

*/


interface Publication 
{
    // ... stávající metody rozhraní
    public function acceptVisitor(Visitor $visitor);
}


interface Visitor 
{
    public function visitLibrary(Library $library);
    public function visitRentalAction(RentalAction $rentalAction);
    public function visitPublication(Publication $publication);
    public function visitMember(Member $member);
}


class Library 
{
    // ... atributy a metody třídy
    public function acceptVisitor(Visitor $visitor) 
    {
        $visitor->visitLibrary($this);

        foreach ($this->rentalActions as $rentalAction) 
        {
            $rentalAction->acceptVisitor($visitor);
        }
    }
}


class RentalAction 
{
    // ... atributy a metody třídy
    public function acceptVisitor(Visitor $visitor) 
    {
        $visitor->visitRentalAction($this);
        $this->publication->acceptVisitor($visitor);
        $this->member->acceptVisitor($visitor);
    }
}


class Member 
{
    // ... atributy a metody třídy
    public function acceptVisitor(Visitor $visitor) 
    {
        $visitor->visitMember($this);
    }
}


class VisitorEcho implements Visitor
{
    public function visitLibrary(Library $library)
    {
        print "Knihovna\n";
    }

    public function visitRentalAction(RentalAction $rentalAction)
    {
        printf(" + Publikace vypůjčená od %s", $rentalAction->getRentDate());
        if ($rentalAction->isReturned()) {
            printf(" do %s\n", $rentalAction->getReturnDate());
        } else {
            print " - dosud nevrácena\n";
        }
    }

    public function visitPublication(Publication $publication)
    {
        printf(" - Kategorie: %s\n", $publication->getCategory());
        printf(" - Počet stran: %d\n", $publication->getPageCount());
    }

    public function visitMember(Member $member)
    {
        printf(" - Čtenář: %s\n", $member->getName());
    }
}


$visitor = new VisitorEcho();
$library->acceptVisitor($visitor);



<?php

class VisitorXMLExport implements Visitor
{
    protected $doc;
    protected $root;
    protected $currentAction = null;

    public function __construct()
    {
        $this->doc = new \DOMDocument('1.0', 'UTF-8');
        $this->doc->formatOutput = true;
    }

    public function visitLibrary(Library $library)
    {
        $this->root = $this->doc->createElement('library');
        $this->doc->appendChild($this->root);
    }

    public function visitRentalAction(RentalAction $rentalAction)
    {
        $this->currentAction = $this->doc->createElement('rentalAction');
        $this->root->appendChild($this->currentAction);
        $this->currentAction->setAttribute(
            'rentDate',
            $rentalAction->getRentDate()
        );
        if ($rentalAction->isReturned()) {
            $this->currentAction->setAttribute(
                'returnDate',
                $rentalAction->getReturnDate()
            );
        }
    }

    public function visitPublication(Publication $publication)
    {
        $tag = $this->doc->createElement('publication');
        $tag->setAttribute('category', $publication->getCategory());
        $tag->setAttribute('pageCount', $publication->getPageCount());
        $this->currentAction->appendChild($tag);
    }

    public function visitMember(Member $member)
    {
        $tag = $this->doc->createElement('member');
        $tag->setAttribute('id', $member->getId());
        $tag->setAttribute('name', $member->getName());
        $this->currentAction->appendChild($tag);
    }

    public function asXML()
    {
        return $this->doc->saveXML();
    }
}


$visitor = new VisitorXMLExport();
$library->acceptVisitor($visitor);
print $visitor->asXML()


On gists

14. Observe

Navrhove vzory - Bohmer

observer.php #

<?php



/*

Definice
---------

Návrhový vzor Observer definuje závislost 1:n mezi subjektem a libovolným počtem
pozorovatelů. Při změně stavu subjektu jsou o této skutečnosti automaticky informovány
všechny pozorovatele.

Pro implementaci tohoto návrhového vzoru jsou nutné následující kroky:
1. Definovat rozhraní (Observer) pro pozorovatele, které vyžaduje jednu
metodu, prostřednictvím níž jsou pozorovatelé informovaní o změně stavu
objektu.

2. Definovat rozhraní (Observable) pro pozorované objekty. Toto rozhraní
musí vyžadovat metody na přidání a odstranění pozorovatelů a také metodu
notify(), pomocí níž jsou pozorovatele informovány o změně stavu
pozorovaného objektu. rozdílem. Pozorovatel žádné hodnoty týkající se pozorovaného objektu – je bezstavový. Tento pozorovatel
tedy může současně pozorovat více objektů. Pozorovatel naopak uchovává informaci, kdy má nastat další pravidelná kontrola – uchovává
určitý stav. Protože se tato hodnota může u různých tiskáren lišit, lze jej použít
jen pro pozorování jednoho objektu. Pro každý další objekt je nutné vytvořit nový objekt pozorovatele.

3. V pozorovaném objektu implementovat rozhraní Observable.
4. Do metod, které mění stav objektu, vložit volání metody notify().
5. Implementovat konkrétní pozorovatele.

*/


interface Printer
{
    public function turnOn();
    public function turnOff();
    public function printPublication(Publication $p, $count = 1);
    public function getType();
    public function getPageCounter();
}

interface Observable 
{
    public function attach(Observer $observer);
    public function detach(Observer $observer);
    public function notify();
}


interface Observer 
{
    public function update(Observable $observable);
}


class LaserPrinter implements Printer, Observable
{
    protected $turnedOn = false;
    protected $type = null;
    protected $pageCounter = 0;

    protected $observers = array();

    function __construct($type)
    {
        $this->type = $type;
    }

    public function turnOn()
    {
        $this->turnedOn = true;
    }

    public function turnOff()
    {
        $this->turnedOff = false;
    }

    public function getType()
    {
        return $this->type;
    }

    public function printPublication(Publication $p, $count = 1)
    {
        if (true !== $this->turnedOn) {
            return false;
        }
        $pageCount = $p->getPageCount();
        $this->pageCounter += $pageCount * $count;

        //  2 OBSERVER
        $this->notify();

        return true;
    }

    public function getPageCounter()
    {
        return $this->pageCounter;
    }

    // OBSERVE THINGS
    public function attach(Observer $observer) 
    {
        $this->observers[] = $observer;
    }
    
    public function detach(Observer $observer)
    {
        $this->observers = array_diff($this->observers, array($observer));
    }

    public function notify() 
    {
        foreach($this->observers as $observer) 
        {
            $observer->update($this);
        }
    }    
}



class ObserverInitialCheck implements Observer
{
    protected $checkPageCounter;

    public function __construct($pageCounter = 10000)
    {
        $this->checkPageCounter = $pageCounter;
    }

    public function update(Observable $observable)
    {
        if (!$observable instanceof Printer) {
            return;
        }

        if ($observable->getPageCounter() >= $this->checkPageCounter) {
            printf(
                "Nutná prvotní kontrola po %d vytištěných stranách.\n",
                $this->checkPageCounter
            );

            $observable->detach($this); 
        }
    }
}


$book = new Book('PC', 580);
$printer = new LaserPrinter('Printer 1');
$initialCheck = new ObserverInitialCheck(10000);
$printer->attach($initialCheck);
$printer->turnOn();
$printer->printPublication($book, 10);
printf("Počet vytištěných stran: %d\n",
$printer->getPageCounter());
$printer->printPublication($book, 10);
printf("Počet vytištěných stran: %d\n",
$printer->getPageCounter());
$printer->turnOff();


/*
Počet vytištěných stran: 5800
Nutná prvotní kontrola po 10000 vytištěných stranách.
Počet vytištěných stran: 11600
*/


class ObserverRegularCheck implements Observer
{
    protected $nextCheck = null;
    protected $interval;

    public function __construct($start, $interval)
    {
        $this->nextCheck = $start;
        $this->interval = $interval;
    }

    public function update(Observable $observable)
    {
        if (!$observable instanceof Printer) {
            return;
        }

        if ($observable->getPageCounter() >= $this->nextCheck) 
        {
            printf(
                "Pravidelná kontrola po %d vytištěných stranách.\n",
                $this->nextCheck
            );
            $this->nextCheck += $this->interval;
        }
    }
}



$book = new Book('PC', 580);
$printer = new LaserPrinter('Printer 1');
$initialCheck = new ObserverInitialCheck(10000);
$regularCheck = new ObserverRegularCheck(40000, 30000);
$printer->attach($initialCheck);
$printer->attach($regularCheck);
$printer->turnOn();

$printer->printPublication($book, 20);
printf("Počet vytištěných stran: %d\n",
$printer->getPageCounter());
$printer->printPublication($book, 60);

printf("Počet vytištěných stran: %d\n",
$printer->getPageCounter());
$printer->printPublication($book, 50);
printf("Počet vytištěných stran: %d\n",
$printer->getPageCounter());
$printer->turnOff();

/*
Nutná prvotní kontrola po 10000 vytištěných stranách.
Počet vytištěných stran: 11600
Pravidelná kontrola po 40000 vytištěných stranách.
Počet vytištěných stran: 46400
Pravidelná kontrola po 70000 vytištěných stranách.
Počet vytištěných stran: 75400
*/