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

Autor wpisu: Tomasz Kowalczyk, dodany: 05.04.2011 06:06, tagi: zend_framework, symfony, php, framework

Konferencja 4Developers to ciekawa inicjatywa wśród spotkań dla ludzi z branży IT w Polsce. Jak możemy przeczytać na stronie głównej projektu: "4Developers to konferencja dla programistów, największe przedsięwzięcie tego typu w Polsce – 400 uczestników, 4 równoległe ścieżki i ponad 30 prelegentów". Ze względu na fakt, że miałem okazję wczoraj (04.04.2011) w tym przedsięwzięciu uczestniczyć, [...]

Autor wpisu: batman, dodany: 31.03.2011 08:00, tagi: zend_framework

Pracując nad jednym z ostatnich projektów, kolejny raz natknąłem się na dosyć powszechny problem. Zdecydowana większość akcji renderuje podobny widok, różniący się kilkoma drobnymi szczegółami. Niestety przeniesienie powtarzających się elementów do layoutu nie wchodzi w grę, ponieważ zależą od aktualnego stanu aplikacji, który znany jest dopiero w akcji. Nie pozostaje więc nic innego jak skorzystanie z helperów widoku lub partiali. Ponieważ oba podejścia nie do końca mi odpowiadają, zacząłem szukać innego rozwiązania, aż w końcu natknąłem się na trzyetapowe layouty (3 step layouts), które nazwałem (nie bez powodu) zagnieżdżonymi.

Cała sztuczka polega na utworzeniu dodatkowej (trzeciej) warstwy znajdującej się nad layoutem. Warstwa ta nazwana wrapperem, zawiera stałe elementy takie jak nagłówek i stopka. Drugą warstwą jest standardowy layout, a ostatnią widok. Najciekawszy w tym podejściu jest fakt, iż wszystko dzieje się w obrębie Zend Frameworka i nie wymaga dodatkowych bibliotek ani nadpisywania gotowych funkcjonalności. Wszystko zapewnia nam Zend_Layout.

Ponieważ dokładny opis rozwiązania znajduje się na stronie jego autora, przedstawię tylko najważniejsze jego elementy.

Zaczniemy od konfiguracji.

; application/configs/application.ini

resources.layout.layoutPath = APPLICATION_PATH "/views/layouts"
resources.layout.layout = wrapper

Następnie musimy przygotować wrapper.

<?php /* application/views/layouts/wrapper.phtml */ ?> 

<?php echo $this->doctype()."\n"; ?>
<html>
    <head>
        <?php echo $this->headTitle(); ?>
        <?php echo $this->headMeta(); ?>
        <?php echo $this->headLink(); ?>
        <?php echo $this->headStyle(); ?>
    </head>
    <body>
        <?php /* NESTED LAYOUT SUPPORT */ ?>
        <?php if($this->layout()->nestedLayout): ?>
            <?php $this->layout()->setLayout($this->layout()->nestedLayout); ?>
        <?php else: ?>
            <?php $this->layout()->setLayout('default'); ?>
        <?php endif;?>
        <?php echo $this->layout()->render();  ?> 

        <?php /* OUTPUT JAVASCRIPT */ ?>
        <?php echo $this->headScript(); ?>
        <?php echo $this->inlineScript(); ?>
    </body>
</html>

A na końcu layout.

<?php /* application/views/layouts/default.phtml */ ?> 

<div class="container">
    <div class="header">
        <h1>My Application</h1>
    </div>
    <div class="body">
        <?php echo $this->layout()->content; ?>
    </div>
    <div class="footer">
        <p>Copyright 2011</p>
    </div>
</div>

Reszta wygląda tak samo jak w przypadku klasycznego dwuetapowego podejścia, czyli przekazanie w akcji danych do widoku i ich wyświetlenie. Z poziomu widoku lub akcji mamy możliwość sterowania zarówno wrapperem jak i layoutem.

Dokładny opis działania przedstawionego powyżej sposobu znajdziecie pod adresem http://3engineers.clariondoor.com/creating-3-step-layouts-with-zendlayout. Oprócz wspomnianych trzech warstw, autor opisuje w jaki sposób automatycznie ładować layout w zależności od modułu oraz dodaje kolejną (czwartą) warstwę layoutu.

Autor wpisu: singles, dodany: 24.03.2011 18:26, tagi: javascript, php, zend_framework

W dzisiejszym wpisie z serii ZFQT chciałbym przybliżyć temat helperów z rodziny head[type]. Oprę się na przykładzie headScript, ponieważ jest on jednym z najczęściej używanych helperów podczas tworzenia aplikacji ZF. Służy do zarządzania/dołączania skryptów JS w ramach naszej aplikacji.

Niektórzy powiedzą pewnie:

Po co mi jakaś klasa do dołączania skryptów? To przecież takie proste jest.

W przypadku większych projektów zdarza się, że posiadamy jeden/dwa główne skrypty – najczęściej jest to jakiś framework JS + biblioteka UI. Jednak, niektóre ze stron naszej aplikacji wymagają specyficznego dla siebie kodu. A dołączanie wszystkich potrzebnych plików dla każdej strony, nawet jeśli nie są one tam wykorzystywane, ciężko nazwać postępowaniem rozsądnym. Najlepiej byłoby załączać najczęściej używane pliki w głównym layoucie, a specyficzne skrypty tylko w przypadku niektórych akcji.

Jeśli by się głębiej nad tym problemem zastanowić, to fajnie byłoby mieć taki „koszyk”, do którego można by wrzucać potrzebne skrypty – w zależności od potrzeb – podczas wykonywania kodu, a wyświetlać je na samym końcu. W takim właśnie celu powstał helper headScript w ZF (oraz jego „bracia”). Konkretniej mówiąc, powstał helper placeholder, po którym wspomniane helpery head dziedziczą. Ich działanie (w skrócie) polega właśnie na agregowaniu tekstu/kodu/danych. Dobre wyjaśnienie znajdziecie w dokumentacji do ZF – jest tam także lista wszystkich klas dziedziczących po placeholder.

Nieprawidłowa kolejność skryptów w przypadku headScript

Jest jeden konkretny powód, dlaczego napisałem, że oprę się na helperze headScript. Otóż to, w przeciwieństwie do jego „braci”, w jego przypadku ważna jest kolejność, w jakiej skrypty dołączone. Prosty przykład – mamy jQuery, jQueryUI oraz kawałek kodu, który wspominane biblioteki wykorzystuje. Po szybkim przejrzeniu dokumentacji pierwsze podejście będzie wyglądało pewnie tak:

<?php echo $this->doctype(Zend_View_Helper_Doctype::HTML5); ?>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>SampleApp</title>
</head>
<body>
    <p>[menu] | [menu] | [menu] | [menu] | [menu] | [menu]</p>
    <?php echo $this->layout()->content ?>
 
<!-- scripts -->
<?php echo $this->headScript()->appendFile('http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js')
                              ->appendFile('ttps://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js'); ?>
</body>
</html>
 
//application/views/index/index.phtml
<div id="dialog-content" title="Basic dialog">
	<p>This is the default dialog which is useful for displaying information. The dialog window can be moved, resized and closed with the 'x' icon.</p>
</div>
<?php $this->headScript()->appendScript(<<<JS
$(document).ready(function(
    //RB używamy pluginu dialog z jQuery UI.
    $('#dialog-content').dialog();
));
JS
);

Dlaczego dołączyłem skrypty na samym końcu? Ponieważ jest to dobra praktyka prowadząca do powstawania wydajniejszych aplikacji – patrz Yahoo Developer Network.

Po uruchomieniu takiego kodu otrzymamy jednak błąd.

error

Błąd JS przy nieprawidłowej kolejności skryptów

Zend Framework najpierw dołączył kod z widoku, a następnie te zdefiniowane w layoucie. Patrz screen:

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

Autor wpisu: singles, dodany: 19.03.2011 23:06, tagi: php, zend_framework

Słowem wstępu – ZFQT – zapytacie pewnie co to znaczy? Nie, nikt nie implementuje Zend Framework’a korzystając bibliotek Qt – przynajmniej nic mi na ten temat nie wiadomo. Skrót ten oznacza Zend Framework Quick Tip. Tym wpisem chciałbym zacząć serię stosunkowo krótkich (postaram się:) notek zawierających porady/sztuczki w ZF. Niektóre mogą się wydawać oczywiste, ale nawet jeśli jedna osoba nauczy się czegoś nowego albo zrozumie dzięki temu, jak działa ZF, to uważam, że i tak warto prowadzić taką serię. Tym bardziej, że także komentarze często zawierają wartościową wiedzę. Tak więc czas zacząć!

Czym jest helper widoku?

View Helpers w ZF to klasy, które najczęściej implementują skomplikowaną logikę powiązaną z widokiem. Reference Guide od ZF opisuje je w ten sposób:

In your view scripts, often it is necessary to perform certain complex functions over and over: e.g., formatting a date, generating form elements, or displaying action links. You can use helper classes to perform these behaviors for you.

W ZF helpery definiujemy domyślnie jako klasy o nazwie pasującej do schematu Zend_View_Helper_[nazwaKlasy] oraz zapisujemy w ścieżce application/views/helpers/ – oczywiście, nazwy klas helperów jak ich lokalizację można zmieniać. Helper musi posiadać metodę o nazwie takiej samej jak nazwa pliku, z tym że zaczynającą się od małej litery. Następnie możemy używać ich w plikach widoku *.phtml poprzez $this->nazwaHelpera() bądź w dowolnym miejscu aplikacji, gdzie mamy dostęp do instancji Zend_View.

Przykład najprostszego helpera, który zwróci odpowiednią formę rzeczownika w zależności od przekazanych parametrów. Zaprogramowany dla większości przypadków języka angielskiego, ponieważ implementacja jest zdecydowanie prostsza, a chodzi o pokazanie zasady działania.

<?php
// application/views/helpers/Pluralize.php
class Zend_View_Helper_Pluralize
{
    public function pluralize($noun, $number)
    {
        return $noun . ((intval($number) > 1) ? 's' : '');
    }
}
 
// application/views/index/index.phtml
<?php echo $this->pluralize('cat', 1); ?> // wyświetla 'cat'
<?php echo $this->pluralize('cat', 4); ?> // wyświetla 'cats'
<?php echo $this->pluralize('screen', 11); ?> // wyświetla 'screens'

Więcej informacji na temat helperów widoku, głównie tych standardowych znajdziecie w Reference Guide:View Helpers

Wiele metod dla jednego helpera

W momencie, kiedy wywołujecie nieistniejącą metodę obiektu widoku, Zend Framework automatycznie szuka klasy helpera pasującej do podanej nazwy. Jeśli takowa istnieje, tworzy obiekt tej klasy i wywołuje metodę zgodną z nazwą klasy – stąd wspomniane wcześniej wymaganie odnośnie nazywania metod. Rozwiązanie takie sprawdza się w większości przypadków.

Załóżmy jednak sytuację, że w naszej aplikacji musimy wyświetlać listę superbohaterów na dwa różne sposoby. Raz jako listę numerowaną, a drugi raz jako ciąg znaków oddzielony przecinkami. W drugim przypadku jednak imię i nazwisko bohatera musi być linkiem do strony wyświetlającej szczegóły na jego temat.

Pierwsza myśl niektórych programistów brzmi zazwyczaj:

no nic, muszę napisać dwie klasy – jedną do wyświetlania listy, drugą do linków oddzielonych przecinkami

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

Autor wpisu: batman, dodany: 17.03.2011 08:00, tagi: php, zend_framework

Praca nad jednym z ostatnich projektów była swojego rodzaju powrotem do przeszłości. Wszystko za sprawą jedynego możliwego sposobu przeniesienia plików na serwer – kopiowanie z dysku lokalnego na serwer. Tak się złożyło, iż projekt ten stworzyłem w Zend Frameworku, który składa się z kilku tysięcy plików. Czas wgrywania plików – dobre kilkanaście minut. Jeśli dołożymy do tego zrywanie połączenia z serwerem do kilkaset plików okazuje się, że pół godziny marnuje się na “pilnowanie uploadu”. Zdeprymowany postępem uploadu zacząłem zastanawiać się nad lepszym rozwiązaniem i wpadłem na pomysł “skompilowania” aplikacji do pojedynczego pliku.

Dosyć szybko okazało, iż zadanie jakie przed sobą postawiłem, jest bardziej niż proste i sprowadza się do napisania trzech wierszy kodu PHP oraz niewielkiej modyfikacji struktury projektu.

Opisane poniżej rozwiązanie jest pomysłem, który wymaga dokładnego przetestowania. Dlatego też nie zalecam jego stosowania w środowiskach produkcyjnych.

Struktura katalogów

Struktura katalogów spakowanego projektu ogranicza się do katalogu public, na który wskazuje domena. Pozostałe katalogi projektu zostaną spakowane do archiwum phar i dołączone w pliku index.php. W zależności od konfiguracji serwera, archiwum phar będzie znajdować się w tym samym katalogu do plik index.php lub katalog wyżej (brak dostępu z poziomu przeglądarki).

dirs

Skrypt pakujący

Skrypt pakujący projekt do archiwum phar wygląda następująco.

$phar = new Phar('/sciezka/zapisu/phar_project.phar', null, 'phar_project.phar');
$phar->buildFromDirectory('/sciezka/do/projektu');
$phar->setStub(
	$phar->createDefaultStub('stub.php', 'stub.php')
);

Te trzy wiersze kodu wystarczą do spakowania projektu. W pierwszym wierszu tworzymy obiekt pakujący. Jako pierwszy argument podajemy nazwę archiwum, drugim są flagi przekazane do klasy rodzica (RecursiveDirectoryIterator), ostatnim alias jakim będziemy się posługiwać podczas odwoływania się do archiwum.

W drugim wierszu wskazujemy katalog (projekt ZF), na podstawie którego utworzone zostanie archiwum. Metoda ta przyjmuje drugi parametr, będący wyrażeniem regularnym ograniczającym pliki dołączone do archiwum. Parametr ten jest opcjonalny.

Ostatni wiersz definiuje główny skrypt archiwum. Skrypt ten zostanie uruchomiony w momencie dołączenia pliku phar do skryptu. Pierwszym argumentem jest skrypt uruchamiany podczas korzystania a pliku phar w wierszu poleceń, drugim skrypt dla aplikacji webowej. Nic nie stoi na przeszkodzie aby był to ten sam plik.

index.php i stub.php

Ostatnia zmiana jaką należy wprowadzić wiąże się bezpośrednio ze zmianą struktury katalogów. Musimy wskazać w pliku index.php, że będziemy korzystać z archiwum phar.

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

Autor wpisu: batman, dodany: 14.03.2011 08:00, tagi: zend_framework

Pracując nad różnymi projektami opartymi o Zend Framework, obserwowałem jakie funkcjonalności najczęściej w tych projektach się powtarzały, by móc przygotować jedną uniwersalną, prostą w przenoszeniu bibliotekę rozwiązującą konkretny problem. Okazało się, że najczęściej potrzebowałem prostej biblioteki do wysyłania powiadomień do użytkowników. Wysyłane informacje były najróżniejsze – od linka potwierdzającego założenie konta w serwisie, po skomplikowany graficzny newsletter. Mając dość ciągłego dłubania i szukania projektu, w którym już to robiłem, stworzyłem jedną uniwersalną bibliotekę do wysyłania powiadomień. Budowa biblioteki jest prosta jak konstrukcja cepa. Jest to jedna abstrakcyjna klasa, po której dziedziczą wszystkie “wysyłacze”, składająca się głównie z setterów i getterów. W celu wyrenderowania treści, która zostanie wysłana do użytkownika, korzysta z Zend_View. Aby zapewnić jak największą elastyczność, podczas ustawiania niezbędnych danych możemy skorzystać ze wspomnianych setterów, Zend_Config lub tablic. W chwili obecnej biblioteka oferuje jedynie wysyłanie maili.

Przykładowy kod wysyłający wiadomość z kontrolera wygląda następująco.

$options = $this->getInvokeArg('bootstrap')->getOption('notification');
$notification = new Batman_Notification_Sender_Mail($options['register']);
$notification->setTo('odbiorca@domena.pl');
$notification->userName = 'Jan Kowalski';
$notification->serviceName = 'Nazwa serwisu';
$notification->send();

Jak się nietrudno domyślić, mamy tutaj do czynienia z potwierdzeniem rejestracji w serwisie. Do konstruktora przekazujemy konfigurację przechowywaną w application.ini. W najprostszej postaci wygląda ona następująco.

notification.register.template.templateName = "confirm_registration.phtml"
notification.register.template.templatePath = APPLICATION_PATH "/layouts/notifications"

Do tego dochodzi konfiguracja klasy wysyłającej wiadomości

notification.register.mail.from = "Rejestracja "
notification.register.mail.subject = "Potwierdzenie rejestracji w serwisie"

Na koniec pozostaje jeszcze plik widoku, do którego poprzez obiekt Zend_View trafiają dane.

<h1>Witaj <?php echo $this->userName; ?></h1>
<p>Właśnie zarejestrowałeś się w serwisie <?php echo $this->serviceName; ?></p>
<p>Dziękujemy!</p>

Dokumentację (jak na razie w języku angielskim), bug tracker, repozytorium oraz pliki do pobrania znajdziecie pod adresem https://github.com/wilgucki/Batman-s-ZF-library. Wszelkie uwagi mile widziane.

Autor wpisu: batman, dodany: 11.03.2011 08:00, tagi: zend_framework

Znacie Lucynę? Podobno jest najlepsza w tym co robi. Jeśli wykażemy się odrobiną cierpliwości i zrozumienia, jest w stanie zrobić dla nas dosłownie wszystko. Można się spotkać z niepochlebnymi uwagami kierowanymi pod jej adresem, jednak kilka godzin spędzonych razem pozwoliło mi uznać te opinie za mocno przesadzone. Wprawdzie poznanie jej zajmuje sporo czasu i dopasowanie się do jej humorów nie należy do najprzyjemniejszych doświadczeń, warto jednak się poświęcić, ponieważ zaowocuje to w przyszłości.

Kim jest Lucyna?

Lucyna, a dokładniej rzecz ujmując, Zend_Search_Lucene, jest silnikiem wyszukiwania w całości napisanym w PHP. Wywodzi się z projektu Apache Lucene, jednak niewiele ma z nim wspólnego. Pozwala ona na indeksowanie różnych treści do postaci wspólnego indeksu, na którym później można wykonywać zapytania zwracające pożądane treści.

Pierwsze spojrzenie

Wszystko zaczyna się od stworzenia indeksu.

$index = Zend_Search_Lucene::create('/sciezka/do/indeksu');

We wskazanej lokalizacji przechowywane będą zaindeksowane dane. Powyższy kod wystarczy wykonać tylko raz, ponieważ jak już indeks zostanie stworzony, możemy się do niego odwoływać jedynie przy pomocy metody open.

$index = Zend_Search_Lucene::open('/sciezka/do/indeksu');

Kolacja przy świecach

Utworzony wcześniej indeks możemy wypełnić dokumentami. Dokument stanowi najmniejszy element indeksu. Można go porównać do pojedynczego wiersza w tabeli w bazie danych. Podobnie jak wiersz, składa się on z pól przechowujących konkretne informacje. Jeśli zaindeksujemy listę filmów, wówczas pojedynczy dokument będzie odpowiadał jednemu filmowi, a pola szczegółom tego filmu, np. tytuł, reżyser, rok produkcji, itd.

W przypadku Zend_Search_Lucene każde pole dokumentu posiada własny typ. Dostępnymi typami są:

  • keyword – pole o takim typie przechowywane jest w indeksie w takiej formie, w jakiej do niego trafi. Nie podlega procesowi tokenizacji, dlatego najlepiej nadaje się do przechowywania dat, adresów url, liczb, identyfikatorów, itp.
  • text – idealne do przechowywania informacji tekstowych
  • binary – służą do przechowywania danych binarnych, np ikona, załącznik
  • unindexed – pola służące jako pojemniki na dane, które nie mogą być wyszukiwane, ale powinny zostać zwrócone w wynikach wyszukiwania
  • unstored – dane dodane do pola oznaczonego tym typem nie są przechowywane w indeksie, ale nadal można je przeszukiwać. Idealnie nadaje się do indeksowania obszernych tekstów. W przypadku tego pola, rzeczywiste dane musimy pobrać z zewnętrznego źródła danych. Indeks przechowuje tylko informacje, że taka dana istnieje.

Tworzenie dokumentów i uzupełnianie ich danych jest niezwykle proste.

$index = Zend_Search_Lucene::open('/sciezka/do/indeksu');
$doc = new Zend_Search_Lucene_Document();
$doc->addField(Zend_Search_Lucene_Field::keyword('data_dodania', '2011-02-03'));
$doc->addField(Zend_Search_Lucene_Field::text('tytul', 'Hello world!'));
$doc->addField(Zend_Search_Lucene_Field::unStored('tresc', 'duzo tekstu...'));
$doc->addField(Zend_Search_Lucene_Field::unIndexed('komentarz_autora', 'jest dobrze'));
$index->addDocument($doc);

Jeśli chcielibyśmy zaindeksować większą ilość danych, wystarczy, że nowe dokumenty będziemy tworzyć i dodawać do indeksu w pętli iterującej po tych danych.

Bliższe poznanie

Stworzyliśmy indeks, wypełniliśmy go danymi, pora na wyszukiwanie. W tej dziedzinie Lucyna jest wyjątkowo elastyczna i oferuje szereg zabawek do przeszukiwania indeksu. Począwszy od parsowania przekazanego ciągu na dedykowanych klasach kończąc.

Zacznijmy od parsowania. W tym wariancie Lucyna zdaje się w zupełności na doświadczenie osoby korzystającej z wyszukiwarki.

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.