Sfoglia il codice sorgente

Finished translating the whole ZF Quickstart tutorial.

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@21669 44c647ce-9c0f-0410-b52a-842ac1e357ba
tomeks 16 anni fa
parent
commit
79beae9b99

+ 18 - 0
documentation/manual/pl/tutorials/quickstart-conclusion.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 19996 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.quickstart.conclusion">
+    <title>Gratulacje!</title>
+
+    <para>
+        Szanowny czytelniku, właśnie ukończyłeś tworzenie swojej pierwszej, prostej aplikacji,
+        która korzysta z najpopularniejszych komponentów Zend Framework. Oprócz tych wykorzystanych,
+        istnieje szereg innych składników, które pomagają przy problemach najczęściej pojawiających
+        się w toku tworzenia aplikacji webowych, takich jak: webserwisy, wyszukiwanie, zapis
+        i odczyt dokumentów <acronym>PDF</acronym>, uwierzytelnianie, autoryzacja i wiele innych.
+        <link linkend="reference">Przewodnik programisty</link> jest idealnym źródłem informacji
+        o komponentach Zend Framework, które były używane w tym rozdziale, jak i o wszystkich
+        pozostałych. Mamy nadzieję, że Zend Framework okaże się dla Ciebie przydatny i - co
+        ważniejsze - dajacy satysfakcje.
+    </para>
+</sect1>

+ 190 - 0
documentation/manual/pl/tutorials/quickstart-create-form.xml

@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20879 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.quickstart.create-form">
+    <title>Tworzenie formularza</title>
+
+    <para>
+        Aby aplikacja książka gości była użyteczna należy umieścić w niej formularz
+        umożliwiający zapis nowych gości.
+    </para>
+
+    <para>
+        W pierwszej kolejności należy utworzyć klasę formularza. Można to osiągnąć poprzez
+        polecenie:
+    </para>
+
+    <programlisting language="shell"><![CDATA[
+% zf create form Guestbook
+Creating a form at application/forms/Guestbook.php
+Updating project profile '.zfproject.xml'
+]]></programlisting>
+
+    <para>
+        Powyższe polecenie utworzy katalog <filename>application/forms/</filename>
+        zawierający plik <filename>Guestbook.php</filename>. Należy umieścić w nim następującą
+        treść:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// application/forms/Guestbook.php
+
+class Application_Form_Guestbook extends Zend_Form
+{
+    public function init()
+    {
+        // Ustawienie metody wysyłki danych formularza na POST
+        $this->setMethod('post');
+
+        // Dodanie elementu do wpisania adresu e-mail
+        $this->addElement('text', 'email', array(
+            'label'      => 'Your email address:',
+            'required'   => true,
+            'filters'    => array('StringTrim'),
+            'validators' => array(
+                'EmailAddress',
+            )
+        ));
+
+        // Dodanie elementu do dodania komentarza
+        $this->addElement('textarea', 'comment', array(
+            'label'      => 'Please Comment:',
+            'required'   => true,
+            'validators' => array(
+                array('validator' => 'StringLength', 'options' => array(0, 20))
+                )
+        ));
+
+        // Dodanie elementu captcha
+        $this->addElement('captcha', 'captcha', array(
+            'label'      => 'Please enter the 5 letters displayed below:',
+            'required'   => true,
+            'captcha'    => array(
+                'captcha' => 'Figlet',
+                'wordLen' => 5,
+                'timeout' => 300
+            )
+        ));
+
+        // Dodanie guzika do wysyłki
+        $this->addElement('submit', 'submit', array(
+            'ignore'   => true,
+            'label'    => 'Sign Guestbook',
+        ));
+
+        // Dodanie zabezpieczenia przed CSRF
+        $this->addElement('hash', 'csrf', array(
+            'ignore' => true,
+        ));
+    }
+}
+]]></programlisting>
+
+    <para>
+        Powyższy formularz definiuje pięć elementów: pole adresu e-mail, pole komentarza, pole
+        <acronym>CAPTCHA</acronym> dla zabezpieczenia przed spamem, guzik wysłania komentarza
+        oraz żeton bezpieczeństwa (przed <acronym>CSRF</acronym>).
+    </para>
+
+    <para>
+        Następnie należy zdefiniować nową akcję <methodname>signAction()</methodname> w kontrolerze
+        <classname>GuestbookController</classname>, która będzie odpowiedzialna za odbiór danych
+        wysłanych przez formularz. Aby utworzyć nową akcję oraz związany z nią view script
+        należy uruchomić następujące polecenie:
+    </para>
+
+    <programlisting language="shell"><![CDATA[
+% zf create action sign Guestbook
+Creating an action named sign inside controller 
+    at application/controllers/GuestbookController.php
+Updating project profile '.zfproject.xml'
+Creating a view script for the sign action method 
+    at application/views/scripts/guestbook/sign.phtml
+Updating project profile '.zfproject.xml'
+]]></programlisting>
+
+    <para>
+        Jak widać z komunikatów, polecenie tworzy metodę <methodname>signAction()</methodname>
+        w kontrolerze oraz odpowiedni widok.
+    </para>
+
+    <para>
+        Teraz należy zapisać logikę aplikacji w treści nowej akcji. Na początek należy sprawdzić
+        czy żądanie zostało otrzymane metodą <acronym>POST</acronym> czy <acronym>GET</acronym>.
+        W przypadku metody <acronym>GET</acronym> zostanie po prostu pokazany formularz do
+        wypełnienia. Jednak dla metody <acronym>POST</acronym> niezbędne będzie sprawdzenie
+        poprawności przesyłanych danych oraz, w przypadku pozytywnej weryfikacji, utworzenie
+        nowego rekordu i zapisanie go w bazie danych. Logika może wyglądać następująco:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// application/controllers/GuestbookController.php
+
+class GuestbookController extends Zend_Controller_Action
+{
+    // w tym miejscu jest indexAction()...
+
+    public function signAction()
+    {
+        $request = $this->getRequest();
+        $form    = new Application_Form_Guestbook();
+
+        if ($this->getRequest()->isPost()) {
+            if ($form->isValid($request->getPost())) {
+                $comment = new Application_Model_Guestbook($form->getValues());
+                $mapper  = new Application_Model_GuestbookMapper();
+                $mapper->save($comment);
+                return $this->_helper->redirector('index');
+            }
+        }
+
+        $this->view->form = $form;
+    }
+}
+]]></programlisting>
+
+    <para>
+        Niezbędna jest również zmiana skryptu widoku
+        <filename>application/views/scripts/guestbook/sign.phtml</filename>
+        tak aby zawierał nastęującą treść:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+<!-- application/views/scripts/guestbook/sign.phtml -->
+
+Please use the form below to sign our guestbook!
+
+<?php
+$this->form->setAction($this->url());
+echo $this->form;
+]]></programlisting>
+
+    <note>
+        <title>Lepszy wygląd formularzy</title>
+
+        <para>
+            Tak powstały formularz nie stanowi wzoru piękna ale należy pamiętać, iż wygląd
+            jest w pełni edytowalny. Więcej informacji można zasięgnąć w
+            <link linkend="zend.form.decorators">rozdziale dotyczącym dekoratorów formularzy</link>.
+        </para>
+
+        <para>
+            Dodatkowo przydatny może się okazać 
+            <link linkend="learning.form.decorators.intro">tutorial dekoratorów formularzy</link>.
+        </para>
+    </note>
+
+    <note>
+        <title>Punkt kontrolny</title>
+
+        <para>
+            Po wejściu pod adres "http://localhost/guestbook/sign" powinien się pokazać formularz
+            książki adresowej:
+        </para>
+
+        <para>
+            <inlinegraphic width="421" scale="100" align="center" valign="middle"
+                fileref="figures/learning.quickstart.create-form.png" format="PNG" />
+        </para>
+    </note>
+</sect1>

+ 764 - 0
documentation/manual/pl/tutorials/quickstart-create-model.xml

@@ -0,0 +1,764 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- EN-Revision: 20879 -->
+<!-- Reviewed: no -->
+<sect1 id="learning.quickstart.create-model">
+    <title>Utworzenie modelu oraz tabeli w bazie danych</title>
+
+    <para>
+        Przed rozpoczęciem należy zastanowić się nad następującym zagadnieniem: gdzie tworzone 
+        klasy będą przechowywane i w jaki sposób będzie można je odnaleźć? Utworzony właśnie
+        domyślny projekt, używa automatycznego dołączania plików (autoloader). Możliwe jest 
+        dołączenie do niego kolejnych autoloaderów tak by umożliwić odnajdywanie tworzonych
+        klas. Typowym rozwiązaniem jest umieszczenie różnych klas w głównym katalogu - w tym
+        wypadku nazwanego <filename>application/</filename> - i nazywanie ich z zachowaniem
+        wspólnego prefiksu.
+    </para>
+
+    <para>
+        Klasa <classname>Zend_Controller_Front</classname> umożliwia tworzenie modułów (modules)
+        - odrębnych części, które same są mini-aplikacjami. W ramach każdego modułu odwzorowywana
+        jest taka sama struktura katalogów jaka jest tworzona przez 
+        narzędzie <command>zf</command> w katalogu  głównym aplikacji. Nazwy wszystkich
+        klas w jednym module muszą rozpoczynać się od wspólnego prefiksu - nazwy modułu.
+        Katalog główny - <filename>application/</filename> również jest modułem (domyślnym)
+        dlatego też jego zasoby zostaną uwzględnione w procesie automatycznego dołączania plików.
+    </para>
+
+    <para>
+        <classname>Zend_Application_Module_Autoloader</classname> oferuje funkcjonalność
+        niezbędną do odwzorowania zasobów modułów na odpowiednie ścieżki katalogów oraz
+        ułatwia zachowanie spójnego standardu nazewnictwa. Instancja tej klasy jest tworzona
+        domyślnie podczas uruchamiania klasy bootstrap. Domyślnym prefiksem używanym przez
+        bootstrap jest "Application" więc modele, formularze oraz klasy tabel będą rozpoczynały
+        się prefiksem "Application_".
+    </para>
+
+    <para>
+        Teraz należy się zastanowić co składa sie na książkę odwiedzin. Typowo będzie w niej
+        lista wpisów z <emphasis>komentarzem</emphasis>, <emphasis>czasem zapisu</emphasis>
+        oraz <emphasis>adresem email</emphasis>. Zakładając użycie bazy danych, pole
+        <emphasis>unikalny identyfikator</emphasis> może również być przydatne. Aplikacja
+        powinna umożliwiać zapis danych, pobranie wpisów pojedynczo oraz wszystkich na raz.
+        Prosty model oferujący opisaną funkcjonalność może przedstawiać się następująco:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// application/models/Guestbook.php
+
+class Application_Model_Guestbook
+{
+    protected $_comment;
+    protected $_created;
+    protected $_email;
+    protected $_id;
+
+    public function __set($name, $value);
+    public function __get($name);
+
+    public function setComment($text);
+    public function getComment();
+
+    public function setEmail($email);
+    public function getEmail();
+
+    public function setCreated($ts);
+    public function getCreated();
+
+    public function setId($id);
+    public function getId();
+}
+
+class Application_Model_GuestbookMapper
+{
+    public function save(Application_Model_Guestbook $guestbook);
+    public function find($id);
+    public function fetchAll();
+}
+]]></programlisting>
+
+    <para>
+        <methodname>__get()</methodname> and <methodname>__set()</methodname> stanowią mechanizmy 
+        ułatwiające dostęp do poszczególnych właściwości oraz pośredniczą w dostępie do innych
+        getterów i setterów. Dziękim nim, można również upewnić się, że jedynie pożądane
+        właściwości będą dostępne.
+    </para>
+
+    <para>
+        Metody <methodname>find()</methodname> oraz <methodname>fetchAll()</methodname> umożliwiają
+        zwrócenie pojedynczego lub wszystkich rekordów natomiast <methodname>save()</methodname>
+        zapisuje dane.
+    </para>
+
+    <para>
+        W tym momencie można zacząć myśleć o skonfigurowaniu bazy danych.
+    </para>
+
+    <para>
+        Na początku należy zainicjować zasób <classname>Db</classname>. Jego konfiguracja
+        jest możliwa na podobnych zasadach jak w przypadku zasobów
+        <classname>Layout</classname> oraz <classname>View</classname>.
+        Można to osiągnąć za pomocą polecenia <command>zf configure db-adapter</command>:
+    </para>
+
+    <programlisting language="shell"><![CDATA[
+% zf configure db-adapter \
+> 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook.db"' \
+> production
+A db configuration for the production has been written to the application config file.
+
+% zf configure db-adapter \
+> 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-testing.db"' \
+> testing
+A db configuration for the production has been written to the application config file.
+
+% zf configure db-adapter \
+> 'adapter=PDO_SQLITE&dbname=APPLICATION_PATH "/../data/db/guestbook-dev.db"' \
+> development
+A db configuration for the production has been written to the application config file.
+]]></programlisting>
+
+    <para>
+        Teraz, po otworzeniu pliku <filename>application/configs/application.ini</filename>
+        można zobaczyć instrukcje, jakie zostały do niego dodane w odpowiednich sekcjach.
+    </para>
+
+    <programlisting language="ini"><![CDATA[
+; application/configs/application.ini
+
+[production]
+; ...
+resources.db.adapter = "PDO_SQLITE"
+resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
+
+[testing : production]
+; ...
+resources.db.adapter = "PDO_SQLITE"
+resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
+
+[development : production]
+; ...
+resources.db.adapter = "PDO_SQLITE"
+resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"
+]]></programlisting>
+
+    <para>
+        Ostatecznie plik konfiguracyjny powinien wyglądać następująco:
+    </para>
+
+    <programlisting language="ini"><![CDATA[
+; application/configs/application.ini
+
+[production]
+phpSettings.display_startup_errors = 0
+phpSettings.display_errors = 0
+bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
+bootstrap.class = "Bootstrap"
+appnamespace = "Application"
+resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
+resources.frontController.params.displayExceptions = 0
+resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
+resources.view[] =
+resources.db.adapter = "PDO_SQLITE"
+resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook.db"
+
+[staging : production]
+
+[testing : production]
+phpSettings.display_startup_errors = 1
+phpSettings.display_errors = 1
+resources.db.adapter = "PDO_SQLITE"
+resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-testing.db"
+
+[development : production]
+phpSettings.display_startup_errors = 1
+phpSettings.display_errors = 1
+resources.db.adapter = "PDO_SQLITE"
+resources.db.params.dbname = APPLICATION_PATH "/../data/db/guestbook-dev.db"
+]]></programlisting>
+
+    <para>
+        Należy zauważyć, iż baza (bazy) danych będzie przechowywana w
+        <filename>data/db/</filename>.
+        Te katalogi powinny zostać utworzone i udostępnione wszystkim. Na systemach unix można
+        tego dokonać następująco: 
+    </para>
+
+    <programlisting language="shell"><![CDATA[
+% mkdir -p data/db; chmod -R a+rwX data
+]]></programlisting>
+
+    <para>
+        Na systemach Windows należy utworzyć odpowiednie katalogi w eksploratorze oraz ustawić
+        uprawnienia w taki sposób aby każdy użytkownik miał prawo zapisu.
+    </para>
+
+    <para>
+        Połączenie z bazą danych zostało utworzone - w tym przypadku bazą jest Sqlite
+        znajdująca się w katalogu <filename>application/data/</filename>. Następnym krokiem jest
+        utworzenie tabeli przechowującej rekordy książki adresowej.
+    </para>
+
+    <programlisting language="sql"><![CDATA[
+-- scripts/schema.sqlite.sql
+--
+-- Poniższy kod SQL należy uruchomić w bazie danych
+
+CREATE TABLE guestbook (
+    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+    email VARCHAR(32) NOT NULL DEFAULT 'noemail@test.com',
+    comment TEXT NULL,
+    created DATETIME NOT NULL
+);
+
+CREATE INDEX "id" ON "guestbook" ("id");
+]]></programlisting>
+
+    <para>
+        Aby mieć zestaw danych do testowania można utworzyć w tabeli kilka rekordów.
+    </para>
+
+    <programlisting language="sql"><![CDATA[
+-- scripts/data.sqlite.sql
+--
+-- Poniższy kod SQL może posłużyć do zapełnienia tabeli testowymi danymi
+
+INSERT INTO guestbook (email, comment, created) VALUES
+    ('ralph.schindler@zend.com',
+    'Hello! Hope you enjoy this sample zf application!',
+    DATETIME('NOW'));
+INSERT INTO guestbook (email, comment, created) VALUES
+    ('foo@bar.com',
+    'Baz baz baz, baz baz Baz baz baz - baz baz baz.',
+    DATETIME('NOW'));
+]]></programlisting>
+
+    <para>
+        Mamy zdefiniowany schemat bazy danych oraz niewielką ilość danych do zaimportowania.
+        Teraz można napisać skrypt tworzący bazę danych. Ten krok nie jest potrzebny w środowisku
+        produkcyjnym. Dzięki niemu można lokalnie wypracować odpowiednią strukturę bazy danych
+        aby tworzona aplikacja działała zgodnie z założeniami. Skrypt
+        <filename>scripts/load.sqlite.php</filename> można wypełnić w poniższy sposób:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// scripts/load.sqlite.php
+
+/**
+ * Skrypt tworzący bazę danych i wypełniający ją danymi
+ */
+
+// Inicjalizacja ścieżek oraz autoloadera
+defined('APPLICATION_PATH')
+    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
+set_include_path(implode(PATH_SEPARATOR, array(
+    APPLICATION_PATH . '/../library',
+    get_include_path(),
+)));
+require_once 'Zend/Loader/Autoloader.php';
+Zend_Loader_Autoloader::getInstance();
+
+// Zdefiniowanie opcji CLI
+$getopt = new Zend_Console_Getopt(array(
+    'withdata|w' => 'Load database with sample data',
+    'env|e-s'    => 'Application environment for which to create database (defaults to development)',
+    'help|h'     => 'Help -- usage message',
+));
+try {
+    $getopt->parse();
+} catch (Zend_Console_Getopt_Exception $e) {
+    // Bad options passed: report usage
+    echo $e->getUsageMessage();
+    return false;
+}
+
+// W przypadku zażądania pomocy, wyświetlenie informacji o użyciu
+if ($getopt->getOption('h')) {
+    echo $getopt->getUsageMessage();
+    return true;
+}
+
+// Inicjalizacja wartości na podstawie opcji CLI
+$withData = $getopt->getOption('w');
+$env      = $getopt->getOption('e');
+defined('APPLICATION_ENV')
+    || define('APPLICATION_ENV', (null === $env) ? 'development' : $env);
+
+// Inicjalizacja Zend_Application
+$application = new Zend_Application(
+    APPLICATION_ENV,
+    APPLICATION_PATH . '/configs/application.ini'
+);
+
+// Inicjalizacja oraz zwrócenie zasobu bazy danych
+$bootstrap = $application->getBootstrap();
+$bootstrap->bootstrap('db');
+$dbAdapter = $bootstrap->getResource('db');
+
+// Powiadomienie użytkownika o postępie (w tym miejscu jest tworzona baza danych)
+if ('testing' != APPLICATION_ENV) {
+    echo 'Writing Database Guestbook in (control-c to cancel): ' . PHP_EOL;
+    for ($x = 5; $x > 0; $x--) {
+        echo $x . "\r"; sleep(1);
+    }
+}
+
+// Sprawdzenie czy plik bazy danych istnieje
+$options = $bootstrap->getOption('resources');
+$dbFile  = $options['db']['params']['dbname'];
+if (file_exists($dbFile)) {
+    unlink($dbFile);
+}
+
+// Wywołanie poleceń zawartych w pliku tworzącym schemat
+try {
+    $schemaSql = file_get_contents(dirname(__FILE__) . '/schema.sqlite.sql');
+    // bezpośrednie użycie obiektu połączenia w celu wywołania poleceń SQL
+    $dbAdapter->getConnection()->exec($schemaSql);
+    chmod($dbFile, 0666);
+
+    if ('testing' != APPLICATION_ENV) {
+        echo PHP_EOL;
+        echo 'Database Created';
+        echo PHP_EOL;
+    }
+
+    if ($withData) {
+        $dataSql = file_get_contents(dirname(__FILE__) . '/data.sqlite.sql');
+        // bezpośrednie użycie obiektu połączenia w celu wywołania poleceń SQL
+        $dbAdapter->getConnection()->exec($dataSql);
+        if ('testing' != APPLICATION_ENV) {
+            echo 'Data Loaded.';
+            echo PHP_EOL;
+        }
+    }
+
+} catch (Exception $e) {
+    echo 'AN ERROR HAS OCCURED:' . PHP_EOL;
+    echo $e->getMessage() . PHP_EOL;
+    return false;
+}
+
+// Ten skrypt powinien zostać uruchomiony z wiersza poleceń
+return true;
+]]></programlisting>
+
+    <para>
+        Teraz należy wywołać powyższy skypt. Można to zrobić z poziomu terminala lub
+        wiersza poleceń poprzez wpisanie następującej komendy:
+    </para>
+
+    <programlisting language="shell"><![CDATA[
+% php scripts/load.sqlite.php --withdata
+]]></programlisting>
+
+    <para>
+        Powinien pojawić się następujący komunikat:
+    </para>
+
+    <programlisting language="text"><![CDATA[
+path/to/ZendFrameworkQuickstart/scripts$ php load.sqlite.php --withdata
+Writing Database Guestbook in (control-c to cancel):
+1
+Database Created
+Data Loaded.
+]]></programlisting>
+
+    <para>
+        Po zdefiniowaniu bazy danych aplikacji książka odwiedzin można przystąpić do budowy kodu
+        samej aplikacji. W następnych krokach zostanie zbudowana klasa dostępu do danych 
+        (poprzez <classname>Zend_Db_Table</classname>), oraz klasa mapująca - służąca do
+        połączenia z wcześniej opisanym modelem.
+        Na koniec utworzony zostanie kontroler zarządzający modelem, którego zadaniem będzie
+        wyświetlanie istniejących rekordów oraz obróbka nowych danych.
+    </para>
+
+    <para>
+        Aby łączyć się ze źródłem danych użyty zostanie wzorzec
+        <ulink url="http://martinfowler.com/eaaCatalog/tableDataGateway.html">Table Data
+        Gateway</ulink> udostępniany poprzez klasę <classname>Zend_Db_Table</classname>.
+        Na początek należy utworzyć klasę opartą o  <classname>Zend_Db_Table</classname>.
+        Podobnie jak przy layoucie oraz adapterze bazy danych - można skorzystać z narzędzia
+        <command>zf</command> i jego komendy <command>create db-table</command>. Należy przy tym
+        podać minimalnie dwa argumenty: nazwę tworzonej klasy oraz nazwę tabeli bazy danych,
+        do której prowadzi.
+    </para>
+
+    <programlisting language="shell"><![CDATA[
+% zf create db-table Guestbook guestbook
+Creating a DbTable at application/models/DbTable/Guestbook.php
+Updating project profile 'zfproject.xml'
+]]></programlisting>
+
+    <para>
+        Spoglądając na strukturę katalogów należy zwrócić uwagę na nowy katalog
+        <filename>application/models/DbTable/</filename> zawierający plik
+        <filename>Guestbook.php</filename>. Ten plik powinien zawierać następującą
+        treść:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// application/models/DbTable/Guestbook.php
+
+/**
+ * This is the DbTable class for the guestbook table.
+ */
+class Application_Model_DbTable_Guestbook extends Zend_Db_Table_Abstract
+{
+    /** Table name */
+    protected $_name    = 'guestbook';
+}
+]]></programlisting>
+
+    <para>
+        Należy zwrócić uwagę na prefiks: <classname>Application_Model_DbTable</classname>.
+        Prefiks klas aplikacji "Application" znajduje się na pierwszym miejscu. Po nim
+        występuje komponent "Model_DbTable", który jest mapowany do katalogu
+        <filename>models/DbTable/</filename> znajdującego się w module.
+    </para>
+
+    <para>
+        Jedyne dane niezbędne przy tworzeniu klasy pochodnej w stosunku do
+        <classname>Zend_Db_Table</classname> to nazwa tabeli i opcjonalnie klucz pierwotny
+        (jeśli jest inny niż "id").
+    </para>
+
+    <para>
+        Teraz należy utworzyć klasę mapującą obiekt w aplikacji na obiekt w bazie danych czyli
+        <ulink url="http://martinfowler.com/eaaCatalog/dataMapper.html">Data Mapper</ulink>.
+        Obiektem w bazie danych jest <classname>Application_Model_Guestbook</classname> natomiast
+        za obiekt bazy danych odpowiada <classname>Application_Model_DbTable_Guestbook</classname>.
+        Typowy API takiej klasy wygląda następująco:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// application/models/GuestbookMapper.php
+
+class Application_Model_GuestbookMapper
+{
+    public function save($model);
+    public function find($id, $model);
+    public function fetchAll();
+}
+]]></programlisting>
+
+    <para>
+        Dodatkowo można zdefiniować metody ustawiające i zwracające Table Data Gateway.
+        Do utworzenia klasy można użyć narzędzia <command>zf</command>:
+    </para>
+
+    <programlisting language="shell"><![CDATA[
+% zf create model GuestbookMapper
+Creating a model at application/models/GuestbookMapper.php
+Updating project profile '.zfproject.xml'
+]]></programlisting>
+
+    <para>
+        Po otwarciu klasy <classname>Application_Model_GuestbookMapper</classname> z lokalizacji
+        <filename>application/models/GuestbookMapper.php</filename> widać następujący kod:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// application/models/GuestbookMapper.php
+
+class Application_Model_GuestbookMapper
+{
+    protected $_dbTable;
+
+    public function setDbTable($dbTable)
+    {
+        if (is_string($dbTable)) {
+            $dbTable = new $dbTable();
+        }
+        if (!$dbTable instanceof Zend_Db_Table_Abstract) {
+            throw new Exception('Invalid table data gateway provided');
+        }
+        $this->_dbTable = $dbTable;
+        return $this;
+    }
+
+    public function getDbTable()
+    {
+        if (null === $this->_dbTable) {
+            $this->setDbTable('Application_Model_DbTable_Guestbook');
+        }
+        return $this->_dbTable;
+    }
+
+    public function save(Application_Model_Guestbook $guestbook)
+    {
+        $data = array(
+            'email'   => $guestbook->getEmail(),
+            'comment' => $guestbook->getComment(),
+            'created' => date('Y-m-d H:i:s'),
+        );
+
+        if (null === ($id = $guestbook->getId())) {
+            unset($data['id']);
+            $this->getDbTable()->insert($data);
+        } else {
+            $this->getDbTable()->update($data, array('id = ?' => $id));
+        }
+    }
+
+    public function find($id, Application_Model_Guestbook $guestbook)
+    {
+        $result = $this->getDbTable()->find($id);
+        if (0 == count($result)) {
+            return;
+        }
+        $row = $result->current();
+        $guestbook->setId($row->id)
+                  ->setEmail($row->email)
+                  ->setComment($row->comment)
+                  ->setCreated($row->created);
+    }
+
+    public function fetchAll()
+    {
+        $resultSet = $this->getDbTable()->fetchAll();
+        $entries   = array();
+        foreach ($resultSet as $row) {
+            $entry = new Application_Model_Guestbook();
+            $entry->setId($row->id)
+                  ->setEmail($row->email)
+                  ->setComment($row->comment)
+                  ->setCreated($row->created);
+            $entries[] = $entry;
+        }
+        return $entries;
+    }
+}
+]]></programlisting>
+
+    <para>
+        W obecnym momencie można przystąpić do utworzenia klasy modelu używając polecenia
+        <command>zf create model</command>:
+    </para>
+
+    <programlisting language="shell"><![CDATA[
+% zf create model Guestbook
+Creating a model at application/models/Guestbook.php
+Updating project profile '.zfproject.xml'
+]]></programlisting>
+
+    <para>
+        Nowo utworzoną klasę można zmodyfikować tak aby ułatwić umieszczanie danych w modelu
+        poprzez przekazanie tablicy do konstruktora lub do metody
+        <methodname>setOptions()</methodname>. Ostatecznie model znajdujący się w
+        <filename>application/models/Guestbook.php</filename> powinien wyglądać następująco:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// application/models/Guestbook.php
+
+class Application_Model_Guestbook
+{
+    protected $_comment;
+    protected $_created;
+    protected $_email;
+    protected $_id;
+
+    public function __construct(array $options = null)
+    {
+        if (is_array($options)) {
+            $this->setOptions($options);
+        }
+    }
+
+    public function __set($name, $value)
+    {
+        $method = 'set' . $name;
+        if (('mapper' == $name) || !method_exists($this, $method)) {
+            throw new Exception('Invalid guestbook property');
+        }
+        $this->$method($value);
+    }
+
+    public function __get($name)
+    {
+        $method = 'get' . $name;
+        if (('mapper' == $name) || !method_exists($this, $method)) {
+            throw new Exception('Invalid guestbook property');
+        }
+        return $this->$method();
+    }
+
+    public function setOptions(array $options)
+    {
+        $methods = get_class_methods($this);
+        foreach ($options as $key => $value) {
+            $method = 'set' . ucfirst($key);
+            if (in_array($method, $methods)) {
+                $this->$method($value);
+            }
+        }
+        return $this;
+    }
+
+    public function setComment($text)
+    {
+        $this->_comment = (string) $text;
+        return $this;
+    }
+
+    public function getComment()
+    {
+        return $this->_comment;
+    }
+
+    public function setEmail($email)
+    {
+        $this->_email = (string) $email;
+        return $this;
+    }
+
+    public function getEmail()
+    {
+        return $this->_email;
+    }
+
+    public function setCreated($ts)
+    {
+        $this->_created = $ts;
+        return $this;
+    }
+
+    public function getCreated()
+    {
+        return $this->_created;
+    }
+
+    public function setId($id)
+    {
+        $this->_id = (int) $id;
+        return $this;
+    }
+
+    public function getId()
+    {
+        return $this->_id;
+    }
+}
+]]></programlisting>
+
+    <para>
+    W ostatnim kroku, aby połączyć wszystkie elementy, należy utworzyć kontroler,
+        którego zadaniem będzie zaprezentowanie listy zapisanych rekordów oraz obsługa
+        dopisania nowych danych.
+    </para>
+
+    <para>
+    Aby to osiągnąć należy użyć polecenia <command>zf create controller</command>:
+    </para>
+
+    <programlisting language="shell"><![CDATA[
+% zf create controller Guestbook
+Creating a controller at
+    application/controllers/GuestbookController.php
+Creating an index action method in controller Guestbook
+Creating a view script for the index action method at
+    application/views/scripts/guestbook/index.phtml
+Creating a controller test file at
+    tests/application/controllers/GuestbookControllerTest.php
+Updating project profile '.zfproject.xml'
+]]></programlisting>
+
+    <para>
+        Powyższe polecenie tworzy nowy kontroler - <classname>GuestbookController</classname>
+        w pliku <filename>application/controllers/GuestbookController.php</filename> zawierający
+        jedną akcję - <methodname>indexAction()</methodname>.
+        Na użytek tego kontrolera utworzony zostaje również katalog widoków:
+        <filename>application/views/scripts/guestbook/</filename> zawierający view skrypt dla
+        akcji index.
+    </para>
+
+    <para>
+        Akcja "index" będzie stanowić domyślny punkt kontrolera pokazujący zapisane rekordy.
+    </para>
+
+    <para>
+        Teraz należy zaprogramować logikę aplikacji. Aby pokazać zapisane rekordy użytkownikowi
+        wchodzącemu do <methodname>indexAction()</methodname> można użyć poniższego kodu:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+// application/controllers/GuestbookController.php
+
+class GuestbookController extends Zend_Controller_Action
+{
+    public function indexAction()
+    {
+        $guestbook = new Application_Model_GuestbookMapper();
+        $this->view->entries = $guestbook->fetchAll();
+    }
+}
+]]></programlisting>
+
+    <para>
+        Dodatkowo potrzebny jest jeszcze widok wyświetlający dane. W pliku
+        <filename>application/views/scripts/guestbook/index.phtml</filename> można umieścić
+        następujący zapis:
+    </para>
+
+    <programlisting language="php"><![CDATA[
+<!-- application/views/scripts/guestbook/index.phtml -->
+
+<p><a href="<?php echo $this->url(
+    array(
+        'controller' => 'guestbook',
+        'action'     => 'sign'
+    ),
+    'default',
+    true) ?>">Sign Our Guestbook</a></p>
+
+Guestbook Entries: <br />
+<dl>
+    <?php foreach ($this->entries as $entry): ?>
+    <dt><?php echo $this->escape($entry->email) ?></dt>
+    <dd><?php echo $this->escape($entry->comment) ?></dd>
+    <?php endforeach ?>
+</dl>
+]]></programlisting>
+
+    <note>
+        <title>Punkt kontrolny</title>
+
+        <para>
+            Teraz, po przejściu do "http://localhost/guestbook" powinna się pojawić lista
+            zapisanych rekordów:
+        </para>
+
+        <para>
+            <inlinegraphic width="525" scale="100" align="center" valign="middle"
+                fileref="figures/learning.quickstart.create-model.png" format="PNG" />
+        </para>
+    </note>
+
+    <note>
+        <title>Użycie skryptu ładującego dane</title>
+
+        <para>
+            Skrypt ładujący dane pokazany we wcześniejszej części tego rozdziału
+            (<filename>scripts/load.sqlite.php</filename>) może zostać użyty do utworzenia
+            bazy danych jak i do zaimportowania przykładowych danych dla każdego środowiska.
+            Wewnętrznie korzysta z klasy <classname>Zend_Console_Getopt</classname>, dzięki
+            czemu możliwe jest podanie parametrów sterujących skryptem. Podając parametr
+            "-h" lub "--help" można zapoznać się z dostępnymi opcjami:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+Usage: load.sqlite.php [ options ]
+--withdata|-w         Load database with sample data
+--env|-e [  ]         Application environment for which to create database
+                      (defaults to development)
+--help|-h             Help -- usage message)]]
+]]></programlisting>
+
+        <para>
+            Parametr "-e" pozwala na nadanie wartości stałej <constant>APPLICATION_ENV</constant>
+            określającej środowisko co, z kolei, umożliwia utworzenie bazy danych SQLite dla
+            każdego środowiska oddzielnie. Należy się upewnić, że skrypt jest uruchamiany z
+            odpowiednią wartością tego parametru dla każdego ze środowisk.
+        </para>
+    </note>
+</sect1>

+ 52 - 52
documentation/manual/pl/tutorials/quickstart-intro-mvc.xml

@@ -8,30 +8,30 @@
         <title>Zend Framework</title>
 
         <para>
-	        Zend Framework to otwarty, zorientowany obiektowo framework aplikacji webowych
-	        przeznaczony dla <acronym>PHP</acronym> 5. ZF jest często określany mianem 'biblioteki
-	        komponentów' ponieważ składa się z wielu, luźno powiązanych komponentów, których można
-	        używać niezależnie od siebie.
-	        Dodatkowo Zend Framework oferuje zaawansowaną implementację
-	        wzorca projektowego Model-Widok-Kontroler
-	        (Model-View-Controller - <acronym>MVC</acronym>),
-	        która może zostać użyta do skonstruowania podstawowej struktury aplikacji.
-	        Pełna lista komponentów Zend Framework razem z krótkim opisem znajduje się w dziale
-	        <ulink url="http://framework.zend.com/about/components">components overview</ulink>.
-	        Wprowadzenie "QuickStart" stanowi wstęp do poznania najczęściej używanych komponentów
-	        Zend Framework, takich jak:
-	        <classname>Zend_Controller</classname>, 
-	        <classname>Zend_Layout</classname>,
-	        <classname>Zend_Config</classname>,
-	        <classname>Zend_Db</classname>,
+            Zend Framework to otwarty, zorientowany obiektowo framework aplikacji webowych
+            przeznaczony dla <acronym>PHP</acronym> 5. ZF jest często określany mianem 'biblioteki
+            komponentów' ponieważ składa się z wielu, luźno powiązanych komponentów, których można
+            używać niezależnie od siebie.
+            Dodatkowo Zend Framework oferuje zaawansowaną implementację
+            wzorca projektowego Model-Widok-Kontroler
+            (Model-View-Controller - <acronym>MVC</acronym>),
+            która może zostać użyta do skonstruowania podstawowej struktury aplikacji.
+            Pełna lista komponentów Zend Framework razem z krótkim opisem znajduje się w dziale
+            <ulink url="http://framework.zend.com/about/components">components overview</ulink>.
+            Wprowadzenie "QuickStart" stanowi wstęp do poznania najczęściej używanych komponentów
+            Zend Framework, takich jak:
+            <classname>Zend_Controller</classname>, 
+            <classname>Zend_Layout</classname>,
+            <classname>Zend_Config</classname>,
+            <classname>Zend_Db</classname>,
             <classname>Zend_Db_Table</classname>,
             <classname>Zend_Registry</classname>, oraz kilku klas pomocniczych (view helpers).
         </para>
 
         <para>
-	        Za pomocą tych komponentów w ciągu kilkudziesięciu minut zostanie utworzona 
-	        prosta aplikacja oparta na bazie danych - księga gości (guest book). Pełny kod
-	        źródłowy tej aplikacji jest dostępny w następujących archiwach:
+            Za pomocą tych komponentów w ciągu kilkudziesięciu minut zostanie utworzona 
+            prosta aplikacja oparta na bazie danych - księga gości (guest book). Pełny kod
+            źródłowy tej aplikacji jest dostępny w następujących archiwach:
         </para>
 
         <itemizedlist>
@@ -55,22 +55,22 @@
         <title>Model-View-Controller</title>
 
         <para>
-	        Tak więc, czym dokładnie jest ten będący na ustach wszystkich wzorzec
-	        <acronym>MVC</acronym>? I dlaczego miałoby to mnie obchodzić?
-	        <acronym>MVC</acronym> to o wiele więcej niż kolejny skrót,
-	        który można mimowolnie wplątać w wypowiedź aby spróbować wywrzeć wrażenie na innych;
-	        z biegiem czasu <acronym>MVC</acronym> nie bez przyczyny stał się standardem
-	        projektowania nowoczesnych aplikacji webowych.
-	        Większość aplikacji sieciowych opiera się w znacznej mierze
-	        na funkcjonalnościach, które można podzielić na trzy kategorie: warstwa prezentacji,
-	        logika biznesowa, dostęp do danych.
-	        Wzorzec <acronym>MVC</acronym> ułatwia zaprojektowanie oprogramowania z
-	        zachowaniem odrębności każdej z tych warstw.
-	        W efekcie kod prezentacji może zostać umieszczony w jednej części aplikacji,
-	        logika biznesowa w drugiej a dostęp do danych w trzeciej.
-	        Wielu deweloperów przekonało się, że dobrze zdefiniowane odseparowanie jest
-	        nieodzowne dla utrzymania kodu w zorganizowanej 
-	        strukturze, zwłaszcza przy projektach wieloosobowych.
+            Tak więc, czym dokładnie jest ten będący na ustach wszystkich wzorzec
+            <acronym>MVC</acronym>? I dlaczego miałoby to mnie obchodzić?
+            <acronym>MVC</acronym> to o wiele więcej niż kolejny skrót,
+            który można mimowolnie wplątać w wypowiedź aby spróbować wywrzeć wrażenie na innych;
+            z biegiem czasu <acronym>MVC</acronym> nie bez przyczyny stał się standardem
+            projektowania nowoczesnych aplikacji webowych.
+            Większość aplikacji sieciowych opiera się w znacznej mierze
+            na funkcjonalnościach, które można podzielić na trzy kategorie: warstwa prezentacji,
+            logika biznesowa, dostęp do danych.
+            Wzorzec <acronym>MVC</acronym> ułatwia zaprojektowanie oprogramowania z
+            zachowaniem odrębności każdej z tych warstw.
+            W efekcie kod prezentacji może zostać umieszczony w jednej części aplikacji,
+            logika biznesowa w drugiej a dostęp do danych w trzeciej.
+            Wielu deweloperów przekonało się, że dobrze zdefiniowane odseparowanie jest
+            nieodzowne dla utrzymania kodu w zorganizowanej 
+            strukturze, zwłaszcza przy projektach wieloosobowych.
         </para>
 
         <note>
@@ -88,29 +88,29 @@
             <itemizedlist>
                 <listitem>
                     <para>
-	                    <emphasis>Model</emphasis> - Ta część aplikacji definiuje jej podstawowe
-	                    funkcjonalności w sposób mniej bądź bardziej abstrakcyjny. Sposób dostępu
-	                    do danych oraz logika biznesowa również mogą być zdefiniowane w tym miejscu.
+                        <emphasis>Model</emphasis> - Ta część aplikacji definiuje jej podstawowe
+                        funkcjonalności w sposób mniej bądź bardziej abstrakcyjny. Sposób dostępu
+                        do danych oraz logika biznesowa również mogą być zdefiniowane w tym miejscu.
                     </para>
                 </listitem>
 
                 <listitem>
                     <para>
-	                    <emphasis>View (Widok)</emphasis> - Ten element definiuje wszystko to co
-	                    zostaje zaprezentowane użytkownikowi. Najczęściej kontrolery przekazują
-	                    dane do każdego z widoków do uformowania i przedstawienia w określonym
-	                    formacie. Poprzez widoki następuje również odebranie danych od użytkownika.
-	                    W tej części będzie się znajdował kod HTML aplikacji <acronym>MVC</acronym>.
+                        <emphasis>View (Widok)</emphasis> - Ten element definiuje wszystko to co
+                        zostaje zaprezentowane użytkownikowi. Najczęściej kontrolery przekazują
+                        dane do każdego z widoków do uformowania i przedstawienia w określonym
+                        formacie. Poprzez widoki następuje również odebranie danych od użytkownika.
+                        W tej części będzie się znajdował kod HTML aplikacji <acronym>MVC</acronym>.
                     </para>
                 </listitem>
 
                 <listitem>
                     <para>
-	                    <emphasis>Controller (Kontroler)</emphasis> - Ten składnik łączy cały 
-	                    wzorzec razem. Kontrolery manipulują modelami, decydują o widoku, jaki
-	                    zostanie zaprezentowany (na podstawie interakcji z użytkownikiem).
-	                    Odpowiadają także za przekazanie danych do widoków lub przekazanie
-	                    kontroli do innego kontrolera. Większość ekspertów MVC zaleca
+                        <emphasis>Controller (Kontroler)</emphasis> - Ten składnik łączy cały 
+                        wzorzec razem. Kontrolery manipulują modelami, decydują o widoku, jaki
+                        zostanie zaprezentowany (na podstawie interakcji z użytkownikiem).
+                        Odpowiadają także za przekazanie danych do widoków lub przekazanie
+                        kontroli do innego kontrolera. Większość ekspertów MVC zaleca
                     <ulink url="http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model">
                         tworzenie możliwie jak najmniejszych kontrolerów</ulink>.
                     </para>
@@ -118,10 +118,10 @@
             </itemizedlist>
 
             <para>
-	            Oczywiście, aby zgłębić temat wzorca <acronym>MVC</acronym>
-	            <ulink url="http://ootips.org/mvc-pattern.html">należałoby go rozwinąć</ulink>
-	            ale dla zrozumienia opisywanej aplikacji - księgi gości - powyższy, minimalny
-	            opis powinien wystarczyć.
+                Oczywiście, aby zgłębić temat wzorca <acronym>MVC</acronym>
+                <ulink url="http://ootips.org/mvc-pattern.html">należałoby go rozwinąć</ulink>
+                ale dla zrozumienia opisywanej aplikacji - księgi gości - powyższy, minimalny
+                opis powinien wystarczyć.
             </para>
         </note>
     </sect2>