Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM    Subskrybuj kanał ATOM dla tagu php Kanał ATOM (tag: php)

Autor wpisu: matipl, dodany: 08.09.2010 11:44, tagi: php, internet

1&1 hosting - logoOd września w Polsce działa znana niemiecka firma 1&1.

Do tej pory swoje oddziały otworzyła m.in. w USA, Wielkiej Brytanii, Francji czy Hiszpanii. Łącznie zarządza 11 mln domen.

Polscy klienci będą obsługiwani przez data center w Karlsruhe (Niemcy). Na początek mamy dostępny tylko jeden produkt, ale za to jaki – 1&1 Pakiet na Dzień Dobry.

  • Domena w pakiecie – 1 .pl
  • administracja DNS
  • Powierzchnia dyskowa – 10 GB (domyślnie 1 GB)
  • Transfer miesięczny – 3000 GB
  • Pojemność skrzynki pocztowej – 2 GB
  • Skrzynki pocztowe z IMAP i POP3 – 100
  • Bazy danych MySQL – 10
  • PHP, Perl, Python
  • Telefoniczna pomoc techniczna: Od poniedziałku do piątku w godzinach od 8:00 do 20:00

Cena: 0 zł

Okres: 2 lata

Załóż konto

Promocja na aktywację darmowego pakietu trwa do 30 listopada 2010 roku. Ich strona dopiero raczkuje, mogą pojawić się jakieś błędy niestety.

Mimo wszystko hosting z 3 TB danych miesięcznie i PHP za darmo, i do tego jeszcze domena .pl. Na pewno warto spróbować, a z czasem na pewno 1&1 poszerzy ofertę w Polsce. Pierwsze testy na 1&1 przeprowadził już m.in. Gachowy.

Autor wpisu: sokzzuka, dodany: 07.09.2010 16:28, tagi: php

W pewnym momencie naszej kariery, gdy popełnimy już troszkę kodu i zaczniemy tworzyć oprogramowanie w skali większej od stronek-wizytówek często zaczynają się pojawiać problemy z utrzymaniem właściwej jakości oprogramowania. Serwisy jakie tworzymy zaczynają mieć coraz bardziej skomplikowane reguły biznesowe. Zaczynamy stosować więc wzorce projektowe i… i czasami nam to wychodzi a czasami nie. Po pewnym czasie gdy nabierze się doświadczenia, można zapytać się samego siebie, czy tak naprawdę poprawiliśmy jakość swojego kodu. Patrząc na stary kod i nowy kod, większość z nas pewnie odpowie, że jakość się znacznie polepszyła, kod jest ładnie sformatowany, nauczyliśmy się pisać klasy, wprowadziliśmy wzorce, w zasadzie wszystko ok. Natomiast wielokrotnie może być to złudne wrażenie. Ciężko jakość kodu ocenić „na oko”. Dlatego też mądrzy ludzie gdzieś w Ameryce (nie łudźmy się, w Polsce by się nie przebili ;P) wymyślili coś takiego jak metryki kodu.

Czym są metryki kodu ?

Metryka jest miarą, dzięki której możemy coś zmierzyć. W tym przypadku metryka kodu będzie pewną miarą kodu, wikipedia podaje kilkanaście rodzajów metryk, jednak w tym artykule chciałbym przedstawić tylko pokrótce te, które można wygenerować za pomocą narzędzia Php Depend. Php Depend jest skryptem php działającym z linii komend, który umożliwia wyliczenie metryk kodu dla plików php.

Jak go używać ?

Po pierwsze, należy go ściągnąć z repozytorium git-a. Na szczęście nie trzeba klonować repozytorium albowiem na git-hub’ie można ściągnąć od razu spakowane paczki. Gdy już rozpakujemy naszego zip’a należy przejść w command line’ie do katalogu z php dependem oraz wydać komendę php pdepend.php --jdepend-chart=ścieżka/chart.svg --summary-xml=ścieżka/metrics.log --overview-pyramid=ścieżka/pyramid.svg ŚĆIEŻKA_DO_ANALIZOWANEGO_KATALOGU. Ta komenda po analizie kodu obecnego w danym katalogu wygeneruje nam trzy pliki:

  • chart.svg – wykres niestabilności do abstrakcji
  • metrics.log – xml z metrykami każdego pliku
  • pyramid.svg – wykres słupkowy z metrykami całego katalogu(paczki)
    • Pliki można obejrzeć pod firefox’em. Natomiast ważniejsze jest to co przedstawiają.

      • Instability – miara tego jak bardzo paczka (zbiór klas) jest odporna na zmiany w innych paczkach tj. jak bardzo zależy od innych paczek. Czym większa niestabilność paczki tym więcej trzeba będzie zmieniać w jej klasach gdy klasy z innych paczek zostaną zmodyfikowane.
      • Abstraction – abstrakcja – ilość klas abstrakcyjnych / interfejsów do sumarycznej ilości klas w paczce
      • LOC – lines of code – ilość lini kodu jakie zawiera paczka
      • CYCLO – cyclomatic complexity – miara skomplikowania kodu, jest proporcjonalna do ilości struktur kontrolnych (if, switch, goto, pętle)
      • NOC – number of children – polega na zliczaniu liczby klas potomnych danej klasy
      • NOP – number of packages – liczba paczek, za paczkę liczy się katalog w tym przypadku
      • NOM- number of methods – liczba metod
      • ANDC – Average Number of Derived Classes: Średnia liczba klas, które bezpośrednio dziedziczą z danej klasy, nie uwzględnia klas zewnętrznych
      • AHH – Average Hierarchy Height: wyliczona średnia drzewa dziedziczenia, nie uwzględnia klas zewnętrznych.

      Wymienione powyżej metryki kodu są metrykami, które można odczytać z obu wykresów i w głównej mierze mają charakter statystyczny / ilościowy, głównie zliczają ilość klas, linii kodu etc. Natomiast najważniejszą rzeczą w mierzeniu oprogramowania jest aspekt jakościowy, postaram się go bardziej zagospodarować w kolejnym artykule ;)

Autor wpisu: Śpiechu, dodany: 06.09.2010 21:25, tagi: php

Tytuł brzmi nieco niedorzecznie, co? Język stworzony do tworzenia stron WWW posłuży nam do manipulowania plikami multimedialnymi. Za sprawą Vladimira Goreja i jego skryptu FFmpeg PHP opublikowanego na phpclasses.org jest to możliwe.

Skrypt korzysta z bibliotek ffmpeg (wersji na Windowsa chyba nie ma). Mając duży plik na serwerze możemy wyciągać z niego takie rzeczy jak czas trwania, liczba klatek na sek., szerokość i wysokość, bitrate i inne. Najistotniejszą dla nas funkcją jest możliwość wyciągnięcia danej klatki z pliku i zapisanie go na dysku w postaci pliku jpg.

Zanim zaczniecie cokolwiek z tym robić proszę o poprawienie linii 635 pliku FFmpegMovie.php na

exec('ffmpeg -ss '.$frameTime.' -i '.escapeshellarg($this->movieFile).' -vframes 1 -sameq '.$frameFilePath.' 2>&1');

Zgłaszałem to autorowi kilka dni temu, ale na razie bez odzewu. Okazuje się, że wywołując ffmpeg z konsoli, kolejność podawanych atrybutów ma kolosalne znaczenie w szybkości działania. Jeżeli wyciągamy klatkę z początku filmu to pal sześć, gorzej jak gdzieś z końca!

Sama obsługa skryptu jest bajecznie prosta: tworzymy sobie obiekt FFmpegMovie i używamy funkcji getFrame().

require_once('./libs/FFmpegMovie.php');
require_once('./libs/FFmpegFrame.php');
 
$ffMovie = new FFmpegMovie('./jakis-plik.avi');
$frameNum = floor($ffMovie->getFrameCount() / 2); // wyciągamy ze środka pliku
$ffMovie->getFrame($frameNum);

Mamy tutaj niestety kilka mankamentów:

  • klatka nie jest takiej samej jakości jak oryginał,
  • klatkę trzeba najpierw wyrzucić jako GD resource za pomocą metody toGDImage() i potem zapisać funkcją imagejpeg(),
  • nie wiemy czy pobrana klatka jest cała czarna (czyli bezużyteczna),
  • nie mamy ładnego wyświetlania z którego momentu filmu pobrano klatkę

Na pierwszy zarzut nic nie pomożemy — jest to wbudowane ograniczenie w ffmpeg, ale za to na resztę można coś zaradzić — stworzyć klasę SpiechuSmartFrame dziedziczącą po FFmpegFrame.

class SpiechuSmartFrame extends FFmpegFrame {
 
    protected $isBlack = null;
 
    /**
     * @return bool
     */
    public function isBlack() {
        if ($this->isBlack == null) {
            $frame = new BlackFrameFinder($this->toGDImage());
            $this->isBlack = $frame->isBlack();
        }
        return $this->isBlack;
    }
 
    /**
     * @return string Returns frame time in hh:mm:ss format
     */
    public function getFrameTimeString() {
        return gmdate("H:i:s",$this->getPts());
    }
 
    /**
     * @param string $filename
     * @param int $quality quality of jpg file (100 best, 0 worst)
     * @return bool true if saving to file was success
     */
    public function saveToJpg($filename, $quality = 85) {
        return imagejpeg($this->toGDImage(), $filename, $quality);
    }
}

Funkcja isBlack() może być dla Was zapewne niezrozumiała. Kod klasy BlackFrameFinder jest na tyle długi, że wkleiłem go do Pastebin. Klasa wykrywa czy obrazek jest czarny w ten sposób:

  • skaluje obrazek źródłowy na kwadrat 24x24 px,
  • zlicza kolory wszystkich pikseli i przelicza je na kolor w skali szarości,
  • zlicza kolory od czarnego do „prawie czarnego” (ja przyjąłem indeksy kolorów od 0–20),
  • porównuje czy przekroczono limit czarnych punktów (przyjąłem więcej niż 70% całości obrazka)

Klasa oczywiście nie jest „przyspawana” do wykrywania wyłącznie czarnych klatek z filmów. Działa na dowolnych obrazach. Jak zwykle możecie robić sobie z nią co chcecie pod warunkiem zostawienia komentarza pochwalnego i kliknięcia na „Lubię to” :-)

Nie zapomnijcie zmodyfikować oryginalnego pliku FFmpegMovie.php w linii 651 na

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: sokzzuka, dodany: 06.09.2010 15:55, tagi: php

Jednym ze wzorców, który pojawia się często w kontekście Domain Driven Design jest wzorzec specyfikacji. Jest to wzorzec, przekształcający reguły biznesowe na logikę Boole’a. Dzięki wzorcowi specyfikacji, możemy w elastyczny sposób sprawdzić, czy dany obiekt spełnia nasze regułu biznesowe. Tłumacząc go na język interfejsów dostajemy coś takiego:

interface ISpecification {
    /**
     * @return boolean
     */
    public function isSatisfiedBy($candidate);
    /**
     * @return ISpecification
     */
    public function andSatisfiedBy(ISpecification $otherSpec);
    /**
     * @return ISpecification
     */
    public function orSatisfiedBy(ISpecifiaction $otherSpec);

    public function not();
}

Metoda isSatisfiedBy sprawdza czy dany obiekt spełnia warunki reguły. Metoda not() neguje nam warunek, natomiast metody „andSatisfiedBy” i „orSatisfiedBy” umożliwiają nam łączenie reguł w łańcuchy. Łańcuchy te będą połączone odpowiednimi operatorami logicznymi – „and” albo „or”.

Poniżej zaprezentuje implementacje na przykładzie kawałka wyimaginowanej aplikacji do obsługi poborowych zrealizowanej w metodyce DDD. Nasz model będzie składał się z trzech klas:

/**
 * @entity
 */

class CPoborowy {
    protected $_pesel;
    protected $_imie;
    protected $_nazwisko;
    protected $_waga;
    protected $_wzrost;
    protected $_ksiazeczkaWojskowa;

    public function __construct($pesel, $imie, $nazwisko, CWaga $waga, CWzrost $wzrost){
        $this->_pesel = $pesel;
        $this->_imie = $imie;
        $this->_nazwisko = $nazwisko;
        $this->_waga = $waga;
        $this->_wzrost = $wzrost;
    }

    public function getWzrost(){
        return $this->_wzrost;
    }

    public function getWaga(){
        return $this->_waga;
    }

    public function zrobJaskolke(){
        echo 'robie jaskolke';
    }

    public function odbierzKsiazeczkeWojskowa(CKsiazeczkaWojskowa $kw){
        if(empty($this->_ksiazeczkaWojskowa)){
            $this->_ksiazeczkaWojskowa = $kw;
            return 'Dziękuje uprzejmie';
        }
        return 'Mam juz ksiazeczke';
    }
}

Klasa „poborowy” reprezentuje nam osobę poborowego, który określony jest kilkoma parametrami ważnymi dla członków komisji uzupełnień – imię, nazwisko, wzrost i waga. Posiada konstruktor, dwa getter’y oraz metody „odberzKsiazeczkeWojskowa” oraz „zrobJaskolke”, które są niezbędne dla logiki biznesowej rekrutacji do wojska ;) . Jak pewnie zauważyliście, w konstruktorze przy parametrach „wzrost” i „waga” mamy typehint’y na CWzrost i CWaga.

/**
 * @value
 */

class CWzrost {

    protected $_wartosc;
    protected $_jednostka;

    public function __construct($wartosc, $jednostka){
        $jednostka = strtolower($jednostka);
        if($wartosc <= 0){
            throw new InvalidArgumentException('Wzrost musi byc wiekszy od 0!');
        }
        if(!in_array($jednostka,array('cm','mm','m'))){
            throw new InvalidArgumentException('Dozwolone jednostki to cm, mm i m');
        }
        $this->_wartosc = $wartosc;
        $this->_jednostka = $jednostka;
    }

    public function __toString(){
        return $wartosc.' '.$jednostka;
    }
}

/**
 * @value
 */

class CWaga {

    protected $_wartosc;
    protected $_jednostka;

    public function __construct($wartosc, $jednostka){
        $jednostka = strtolower($jednostka);
        if($wartosc <= 0){
            throw new InvalidArgumentException('Waga musi byc wiekszy od 0!');
        }
        if($jednostka != 'kg'){
            throw new InvalidArgumentException('Dozwolona jednostka to kilogram');
        }
        $this->_wartosc = $wartosc;
        $this->_jednostka = $jednostka;
    }

    public function __toString(){
        return $wartosc.' '.$jednostka;
    }
}

Obie klasy są tzw. ValueObject’s. W odróżnieniu od poborowego, który jest encją i posiada swój unikalny identyfikator w postaci książeczki wojskowej czy pesel-u, wzrost i waga są bytami nieidentyfikowalnymi – można je rozróżnić tylko po wartości, ubranie tych wartości w klasy ma za zadanie:

  • wyróżnienie ich jako ważnej części języka domeny i modelu
  • walidacje

gdy przyjrzymy się głębiej, widzimy, że w konstruktorach obu klas zawarta jest logika walidacji – zarówno waga jak i wzrost nie mogą być mniejsze od zera, są też sprawdzane jednostki obu wielkości, w końcu nasza komisja poborowa jest w Polsce gdzie mamy jednostki układu SI. Przejdźmy jednak do sedna, czyli wzorca specyfikacji. Załóżmy, że komisja poborowa kwalifikuje do wojska tylko poborowych o wzroście równym 180 cm i wadze 80 kg. Te dwa warunki tworzą naszą specyfikacje, implementacja będzie wyglądać tak:

class CWzrostSpec extends ASpecification {

    protected $_wzrost;

    public function __construct($wzrost){
        $this->_wzrost = $wzrost;
    }

    public function isSatisfiedBy($candidate){
        if($candidate->getWzrost() == $this->_wzrost){
            if(isset($this->_and)){
                return $this->_and->isSatisfiedBy($candidate);
            }
            return true;
        } elseif(isset($this->_or)) {
            return $this->_or->isSatisfiedBy($candidate);
        }
        return false;
    }
}

class CWagaSpec extends ASpecification {
    protected $_waga;

    public function __construct($waga){
        $this->_waga = $waga;
    }

    public function isSatisfiedBy($candidate){
        if($candidate->getWaga() == $this->_waga){
            if(isset($this->_and)){
                return $this->_and->isSatisfiedBy($candidate);
            }
            return true;
        } elseif(isset($this->_or)) {
            return $this->_or->isSatisfiedBy($candidate);
        }
        return false;
    }

}

Przykład użycia:

//okreslamy specyfikacje
$oSpec = new CWzrostSpec(new CWzrost(180,'cm'));
$oSpec->andSatisfiedBy(new CWagaSpec(new CWaga(80,'kg')));

//tworzymy poborowych
$oPoborowy1 = new CPoborowy('123456','Franek', 'Gondala', new CWaga(80,'kg'), new CWzrost(180,'cm'));
$oPoborowy2 = new CPoborowy('789123', 'Max', 'Perreira', new CWaga(72,'kg'), new CWzrost(176,'cm'));

//sprawdzamy czy poborowi spelniaja nasze kryterium
var_dump($oSpec->isSatisfiedBy($oPoborowy1));
var_dump($oSpec->isSatisfiedBy($oPoborowy2));

Dzięki zastosowaniu wzorca specyfikacji, gdy komisja poborowa dostanie nowe wytyczne z Ministerstwa Obrony, będzie można w łatwy sposób zmienić lub dołożyć nowe warunki.

Jak widzimy wzorzec specyfikacji przydaje się przy walidacji obiektów, do walidacji formularzy wystarczyło by jeszcze dodanie metody, która dała by jakąś zwrotną informację o tym, w którym miejscu obiekt nie spełnia specyfikacji. Ponadto wzorca specyfikacji używa się jeszcze w kontekście budowania zapytań do bazy danych a dokładniej do repozytorium. Jak wspomniałem we wcześniejszych artykułach z serii o DDD, repozytorium, jest klasą, która pozwala nam wyszukiwać wcześniej utrwalone obiekty wg pewnych kryteriów. Zamiast więc w klasie repozytorium tworzyć metody typu „findByFirstName”, „findByLastName”, „findBy[a-z0-9_]+” można mieć jedną metodę „find”, która jako argument będzie pobierała obiekt specyfikacji i na jego podstawie tworzyła zapytanie do bazy danych.

Jak zwykle czekam na wszelki feedback ;) .

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Zyx, dodany: 03.09.2010 12:52, tagi: php

Mam przyjemność poinformować, że po prawie roku prac Open Power Template 2.1 wchodzi w fazę beta-testów. Jak to już ze mną bywa, każda gałąź musi być rewolucyjną ewolucją, i choć powstawała ona w bólach, udało mi się właśnie dociągnąć ją do kolejnego etapu prac. Jednocześnie wydałem OPT 2.0.6, który poprawia cztery błędy w gałęzi stabilnej.

Autor wpisu: sokzzuka, dodany: 29.08.2010 00:22, tagi: php

Dzisiejsze spotkanie z Zend’owym Front Controllerem i pluginami natchnęło mnie do kilku przemyśleń. Jednym z nich jest sposób jego działania. Aby w jakiś sposób ingerować w działanie FC należy albo napisać własną implementację jednej z koniecznych do życia przez FC klas (Dispatcher, Router etc) albo w przypadku mniejszych potrzeb stworzyć nowy plugin. Plugin’y są klasami, które reagują na określone zdarzenia typu preDispatch, postDispatch etc. Rozwiązanie to funkcjonuje i ma się dobrze. Wiem również ze słyszenia, że w innych frameworkach stosuje się podobne rozwiązania ale oparte np na sygnałach czy event handler’ach. Ja natomiast chciałbym przedstawić trochę alternatywne podejście do problemu oparte na wzorcu chain of responsibility. Czym jest ten wzorzec ? Generalnie jest on podobny do wzorca obserwator.

class ObserverOne implements SplObserver {
 
    public function update(SplSubject $subject) {
        echo $subject->getMessage().'One';
    }
 
}
 
class ObserverTwo implements SplObserver {
 
    public function update(SplSubject $subject) {
        echo $subject->getMessage().'Two';
    }
 
}
 
class Subject implements SplSubject {
    /**
     *
     * @var array<SplObserver> 
     */
    protected $_observers;
 
    public function attach(SplObserver $observer) {
        $this->_observers[] = $observer;
    }
 
    public function detach(SplObserver $observer) {
        $mKey = array_search($observer, $this->_observers);
        if($mKey !== false){
            unset($this->_observers[$mKey]);
        }
    }
 
    public function notify() {
        foreach($this->_observers as $observer){
            $observer->update($this);
        }
    }
 
    public function getMessage(){
        return 'Aloha !';
    }
 
}
 
$oSubject = new Subject();
$oSubject->attach(new ObserverOne());
$oSubject->attach(new ObserverTwo());
$oSubject->notify();
//Aloha!One Aloha!Two

Oba wzorce dają szanse kilku handler’om na obsłużenie jakiegoś zdarzenia. We wzorcu obserwatora po każdym wystąpieniu zdarzenia wszystkie zarejestrowane handler’y są powiadamiane równocześnie i decydują czy obsłużyć zdarzenie czy nie. Natomiast we wzorcu łańcucha odpowiedzialności powiadamiane są one w określonej kolejności. W klasycznej odmianie tego wzorca tylko jeden handler obsługuje event:

abstract class ChainElement {
 
    protected $_next;
 
    public function setNext(ChainElement $element) {
        $this->_next = $element;
        return $this;
    }
 
    public abstract function run($event);
}
 
class HandlerOne extends ChainElement {
 
    public function run($event) {
        if ($event == 1) {
            echo 'matched one!';
            return;
        }
        if (isset($this->_next)) {
            $this->_next->run($event);
        }
    }
 
}
 
class HandlerTwo extends ChainElement {
 
    public function run($event) {
        if ($event == 2) {
            echo 'matched two!';
            return;
        }
        if (isset($this->_next)) {
            $this->_next->run($event);
        }
    }
 
}
 
class HandlerThree extends ChainElement {
 
    public function run($event) {
        if ($event == 3) {
            echo 'matched three!';
            return;
        }
        if (isset($this->_next)) {
            $this->_next->run($event);
        }
    }
 
}
 
$oElement1 = new HandlerOne();
$oElement2 = new HandlerTwo();
$oElement3 = new HandlerThree();
 
$oElement1->setNext($oElement2);
$oElement2->setNext($oElement3);
 
$oElement1->run(3);
//matched three!

Generalnie można by powiedzieć, że klasyczny chain of responsibility zastępuje wyrażenie switch w sposób bardziej wyrafinowany. Pewnie już do tego momentu co uważniejsi z Was policzyli że użyłem słowa klasyczny co najmniej 2 razy. Oznacza to, że musi istnieć też wersja „nieklasyczna”. Jak już mówiłem wcześniej, w wersji klasycznej przechodzimy do następnego elementu łańcucha tylko kiedy aktualny stwierdza, że nie potrafi obsłużyć żądania, w innym przypadku łańcuch kończy się na aktualnym elemencie. Klasycznym przykładem takiej implementacji wzorca jest Zend_Router, w którym route’y można spinać w łańcuchy, dopasowanie trwa do pierwszego dobrego wzorca.

Są generalnie dwa alternatywne podejścia, pierwsze, różni się tym, że zawsze przelatywany jest cały łańcuch. Natomiast drugie, jest wariacją pierwszego i polega na przeniesieniu logiki sterowania łańcuchem na zewnątrz – zewnętrzny kod decyduje o przebiegu łańcucha.

Moje alternatywne podejście do FrontControllera będzie opierać się na tej drugiej wersji implementacji alternatywnej wzorca łańcucha odpowiedzialności. W podejściu tym będziemy mieli klasę RequestHandler:

class RequestHandler {
    /**
     *
     * @var array
     */
    protected $_chain;
 
    public function addElement(IChainElement $element) {
        $this->_chain[] = $element;
    }
 
    public function handle($request, $server) {
 
        if (empty($this->_chain)) {
            throw new Exception('No processing elements defined');
        }
 
        $aData = array(
            'request' => array(
                'input' => $request,
                'server' => $server
            ),
            'response' => array(
                'headers' => array(),
                'content' => ''
            )
        );
 
        foreach ($this->_chain as $element) {
            $aData = $element->process($aData);
        }
 
        return $aData['response'];
    }
}

Obiekt tej klasy jest nadzorcą łańcucha. Do dodawania elementów do łańcucha służy metoda addElement, która przyjmuje argumenty typu IChainElement, jest to interfejs, który muszą implementować wszystkie elementy łańcucha:

interface IChainElement {
    public function process($input);
}

Następnie gdy dodamy już elementy, wywołujemy metodę handle($request, $server). Jak się pewnie domyślacie $request zwykle będzie superglobalną zmienną $_REQUEST natomiast $server to $_SERVER. Dlaczego tak to zaimplementowałem zamiast po prostu używać tych zmiennych wewnątrz metody ? Zwiększa to testowalność tej klasy i czytelność kodu. Metoda handle przelatuje po wszystkich elementach łańcucha, które przetwarzają w kolejności dodania nasz ‘request’ generując ‘response’.

Dla przykładu konkretnego działania stworzyłem dwa elementy łańcucha, które są niezbędne by osiągnąć minimalną funkcjonalność Front Controller’a. Są to router:

class SampleRouter implements IChainElement {
 
    protected $_mapping;
 
    public function __construct() {
        $aMapping = array(
            'foo*' => 'foobar',
            'baz*' => 'foobaz'
        );
 
        $this->_mapping = $aMapping;
    }
 
    public function process($input) {
        $sHref = $input['request']['server']['REQUEST_URI'];
 
        foreach ($this->_mapping as $pattern => $viewId) {
            if (preg_match("/$pattern/i", $sHref)) {
                $input['request']['viewId'] = $viewId;
                return $input;
            }
        }
        $input['request']['viewId'] = '404';
        return $input;
    }
 
}

oraz Dispatcher:

class SampleDispatcher implements IChainElement {
 
    public function process($input) {
        //If the content exists - cache etc
        if(!empty($input['response']['content'])){
            return $input;
        }
 
        if($input['request']['viewId'] == '404'){
            $input['response']['headers'][] = 'HTTP/1.0 404 Not Found';
            $input['response']['content'] = 'Sorry page not found';
            return $input;
        }
 
        if($input['request']['viewId'] == 'foobar'){
            $input['response']['content'] = 'Foobar page!';
            return $input;
        }
 
        if($input['request']['viewId'] == 'foobaz'){
            $input['response']['content'] = 'FoobaZZZ page!';
            return $input;
        }
 
        return $input;
    }
 
}

Użycie:

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: batman, dodany: 28.08.2010 12:02, tagi: php

Filtry strumieni w PHP można porównać do filtrów znanych z Zend Framework. Są to klasy, które automatyzują czynności związane z odczytywaniem i zapisywaniem danych ze strumienia. Do jednego strumienia można dodać wiele filtrów, dzięki czemu programista zyskuje możliwość dowolnej modyfikacji strumienia.

Najprostszym i zarazem najlepszym przykładem zastosowania filtrów, będzie odczyt pliku i zmiana kodowania treści zawartych w pliku. W tym celu posłużę się plikiem CSV wygenerowanym z dokumentu Excel.

Typowy skrypt odczytujący dane z pliku wygląda następująco

$fp = fopen('./Book1.csv', 'r');
$output = '';
while(!feof($fp)) {
    $output .= fread($fp, 1024);
}
fclose($fp);
echo $output;

Jeśli dane w pliku nie spełniają naszych oczekiwań, wykonywane są operacje mające na celu dostosowanie ich do naszych wymagań. Sprowadza się to do wywołania funkcji zmieniającej kodowanie, zmieniającej wielkość liter, czy podmianie części danych. Jeśli zamiast tego zastosujemy filtr, odebrane dane będą od razu w pożądanej przez nas postaci.

Filtr jest klasą, która dziedziny po klasie php_user_filter. Klasa ta zawiera trzy właściwości oraz trzy metody.

Dostępne właściwości to:

  • filtername – nazwa filtru, który jest aktualnie wykorzystywany
  • params – zawiera parametry przekazane do filtra
  • stream – strumień, który aktualnie jest filtrowany

Dostęne metody:

  • onCreate – metoda wywołana przed rozpoczęciem filtrowania danych. Musi zwrócić true w przypadku poprawnego wykonania zawartych w swoim ciele operacji lub false jeśli operacje zakończyły się niepowodzeniem.
  • onClose – metoda wywołana po zakończeniu filtrowania.
  • filter – metoda odpowiedzialna za filtrowanie danych. Jest to jedyna etoda, która jest wymagana w klasie filtra. Przyjmuje cztery parametry:
    • $in – zasób wskazujący na bucket bridge, który zawiera kolejne porcje danych do filtrowania
    • $out – zasób wskazujący na bucket bridge do którego zostaną zapisane przefiltrowane dane
    • $consumed – parametr ten musi być przekazany przez referencję. Do jego wartości dodawana jest ilość aktualnie filtrowanych danych
    • $closing – parametr określający, że filtrowanie strumienia jest w ostatniej iteracji.

Metoda filter musi zwrócić jedną z trzech wartości:

  • PSFS_PASS_ON – filtrowanie zakończone sukcesem, na wyjście zwrócone zostały jakieś dane.
  • PSFS_FEED_ME – filtrowanie zakończone sukcesem, na wyjście nie zwrócono żadnych danych.
  • PSFS_ERR_FATAL – filtrowanie zakończone niepowodzeniem i nie może być kontynuowane.

Wykorzystując powyższe informacje, napiszemy klasę filtrującą, która zmieni kodowanie pliku na UTF.

class StreamFilterConvertEncoding extends php_user_filter
{
    public function filter($in, $out, &$consumed, $closing)
    {
        while($bucket = stream_bucket_make_writeable($in)) {
            $bucket->data = iconv('CP1250', 'UTF-8', $bucket->data);
            $consumed += $bucket->datalen;
            stream_bucket_append($out, $bucket);
        }
        return PSFS_PASS_ON;
    }
}

W powyższym kodzie tylko dwie funkcje mogą być niezrozumiałe. Pierwszą z nich jest stream_bucket_make_writeable. Zadaniem tej funkcji jest odebranie danych z wejścia i przekształcenie ich w bucket, na którym wykonywane są dalsze operacje. Drugą “egzotyczną” funkcją jest stream_bucket_append, która zapisuje dane z bucketa, do zmiennej wyjściowej. Zmienna $bucket jest obiektem klasy stdClass i zawiera zasób (właściwość bucket), dane (właściwość data) oraz wielkość odczytanych danych (właściwość datalen).

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.