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

Autor wpisu: batman, dodany: 08.10.2010 08:00, tagi: jquery, zend_framework

Czym jest serwis internetowy? Jest to zbiór formularzy oraz danych dodanych przy pomocy tych formularzy. Gdyby nie formularze, Internet taki jakim go znamy. Wyobrażacie sobie w jaki sposób dodawalibyście cokolwiek na ścianę facebooka bez formularzy?

W przypadku formularzy najczęstszym schematem jest ścieżka:

  • strona początkowa (informacje na temat formularza lub dane zebrane przy jego pomocy)
  • formularz (obsługa błędów, operacje na wprowadzonych danych)
  • strona końcowa (podziękowania za wysłanie formularza lub powrót do strony początkowej).

Prawda, że nudne? Okazuje się, że wyrwanie się z tego schematu wcale nie jest takie trudne. Wystarczy formularz wyświetlić na warstwie, a dane zapisać AJAXem w tle. Oczywiście nie można zapomnieć o sytuacji kryzysowej, w której z jakiegoś powodu (np. błąd w skrypcie) zostaliśmy pozbawieni możliwości korzystania z Javascript.

Wszystko to, co przed chwilą opisałem można zrealizować niewielkim nakładem prac przy pomocy komponentu Zend_Form, biblioteki jQuery oraz pluginu FancyBox. Najciekawsze w tym wszystkim jest to, iż nie musimy wcale pisać dodatkowego kodu. Wszystkim zajmą się mechanizmy wbudowane w Zend Frameworka oraz konwencja, której trzeba się trzymać podczas stosowania tego sposobu.

Zacznijmy od formularza. Będzie to prosty formularz zbierający dane o użytkownikach (w przykładzie wykorzystałem klasę Batman_Form opisaną we wpisie Uniwersalne dekorowanie Zend_Form).

class Application_Form_FancyboxExample extends Batman_Form
{
    protected function _renderForm()
    {
        $this->setName('form_fancybox_example');
        $this->setAction('/index/fancyboxform');

        $firstname = new Zend_Form_Element_Text('firstname');
        $firstname->setLabel('Imie')
                  ->setRequired(true)
                  ->addValidator(new Zend_Validate_NotEmpty(), true);

        $lastname = new Zend_Form_Element_Text('lastname');
        $lastname->setLabel('Nazwisko')
                 ->setRequired(true)
                 ->addValidator(new Zend_Validate_NotEmpty(), true);

        $submit = new Zend_Form_Element_Submit('btn_save');
        $submit->setLabel('Zapisz')
               ->setIgnore(true);

        $this->addElement($firstname);
        $this->addElement($lastname);
        $this->addElement($submit);
    }
}

Kluczowym tutaj elementem jest zastosowanie akcji, która jednoznacznie wskazuje na akcję, odpowiedzialną za przetworzenie formularza. Ten prosty zabieg umożliwi nam obsłużenie formularza w przypadku braku Javascript.

Następnie musimy stworzyć widok, który będzie zawierał link do formularza.

<a href="/index/fancyboxform" id="link">dodaj uzytkownika</a>

Na koniec pozostaje stworzenie akcji

public function fancyboxformAction()
{
    $form = new Application_Form_FancyboxExample();
    if($this->_request->isPost()) {
        $postData = $this->_request->getPost();
        if($form->isValid($postData)) {

            // zrob cos z danymi

            $this->_redirect('/index/fancyboxexample');
        }
    }
    $this->view->form = $form;
}

i widoku z formularzem.

<h1>Formularz</h1>
<?php echo $this->form; ?>

Jak dotąd nie zrobiliśmy nic ponad stworzenie standardowego, nudnego formularza wraz z jego obsługą. Pora na magię.

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

Autor wpisu: batman, dodany: 02.10.2010 21:00, tagi: zend_framework

Podczas pracy z Zend_Db_Table bardzo doskwierał mi brak metod, które automatycznie pobierałyby dane na podstawie nazwy metody. A co robi programista, któremu brakuje jakiejś funkcjonalności? Sam ją dopisuje. Po połączeniu tej funkcjonalności z automatycznym tworzeniem obiektu DbTable, powstał “magiczny model”.

Jeśli nie wiecie o czym piszę, za chwilę wszystko stanie się jasne. Załóżmy, że mamy w bazie danych tabelę users, o następującej strukturze (baza MySQL):

CREATE  TABLE IF NOT EXISTS `batman`.`users` (
  `iduser` INT NOT NULL AUTO_INCREMENT ,
  `login` VARCHAR(50) NULL ,
  `password` VARCHAR(32) NULL ,
  `firstname` VARCHAR(150) NULL ,
  `lastname` VARCHAR(250) NULL ,
  `email` VARCHAR(250) NULL ,
  PRIMARY KEY (`iduser`) )
ENGINE = InnoDB

Jeśli chcielibyśmy stworzyć metody zwracające kolekcje przefiltrowane według którejś z kolumn, musielibyśmy napisać szereg metod, np getUsersByLogin, czy getUsersByFirstname. Im więcej kolumn, po których chcielibyśmy zwracać dane, tym więcej czeka na pracy.

Z pomocą przychodzi magiczna metoda __call (stąd robocza nazwa “magiczny model”). Wystarczy, że w metodzie tej sprawdzimy dla jakiej kolumny chcemy pobierać dane. Resztą zajmie się “magia”.

public function __call($method, array $args)
{
    if(!isset($args[0])) {
        throw new Exception('You have to pass at least one argument in this magic');
    }

    $name = $this->getDbTable()->info(Zend_Db_Table_Abstract::NAME);
    $conditionCol = strtolower(
        str_ireplace('get' . $name . 'by', '', $method)
    );

    $cols = $this->getDbTable()->info(Zend_Db_Table_Abstract::COLS);
    if(!in_array($conditionCol, $cols)) {
        throw new Exception('What are you looking for? "' . $method . '" is invalid in this model');
    }

    $select = $this->getDbTable()->select();
    $select->where($conditionCol . ' = ?', $args[0]);

    return $this->getDbTable()->fetchAll($select);
}

Metoda najpierw sprawdza, czy przekazany został parametr, według którego będziemy pobierać dane. Następnie z nazwy metody usuwamy wszystkie zbędne elementy tak, by pozostała nam rzeczywista nazwa kolumny. Oczywiście musimy sprawdzić, czy wskazana kolumna znajduje się w odpytywanej tabeli. Na koniec wykorzystywana jest metoda fetchAll, do pobrania przefiltrowanych danych.

Wracając do naszej przykładowej tabeli. Jeśli powyższa metoda znajdzie się w modelu, wówczas zapis getUsersByFirstname(‘Anna’), spowoduje, że z tabeli pobrani zostaną wszyscy użytkownicy (a raczej użytkowniczki), których imię to Anna.

Pełny kod klasy wygląda następująco

abstract class Batman_Model
{
    /**
     * @var Zend_Db_Table_Abstract
     */
    protected $_dbTable = null;

    public function __construct()
    {
        $classParts = explode('_', get_class($this));
        $className = array_pop($classParts);
        array_push($classParts, 'DbTable', $className);
        $dbTableClassName = implode('_', $classParts);
        $this->_dbTable = new $dbTableClassName();
    }

    /**
     * @return Zend_Db_Table_Abstract
     */
    public function getDbTable()
    {
        if($this->_dbTable === null) {
            throw new Exception('There id no db table object');
        }
        return $this->_dbTable;
    }

    /**
     * @return Zend_Db_Table_Rowset_Abstract
     */
    public function __call($method, array $args)
    {
        if(!isset($args[0])) {
            throw new Exception('You have to pass at least one argument in this magic');
        }

        $name = $this->getDbTable()->info(Zend_Db_Table_Abstract::NAME);
        $conditionCol = strtolower(
            str_ireplace('get' . $name . 'by', '', $method)
        );

        $cols = $this->getDbTable()->info(Zend_Db_Table_Abstract::COLS);
        if(!in_array($conditionCol, $cols)) {
            throw new Exception('What are you looking for? "' . $method . '" is invalid in this model');
        }

        $select = $this->getDbTable()->select();
        $select->where($conditionCol . ' = ?', $args[0]);

        return $this->getDbTable()->fetchAll($select);
    }
}

Przykład użycia:

model i db table

class Application_Model_User extends Batman_Model
{
}

class Application_Model_DbTable_User extends Zend_Db_Table_Abstract
{
	protected $_name = 'users';
}

Kod w kontrolerze:

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

Autor wpisu: Kamil, dodany: 30.09.2010 02:41, tagi: zend_framework, javascript, apache

Nie ma wątpliwości, że praca programisty polega na ciągłym rozwoju i doskonaleniu swoich umiejętności, szlifowaniu wiedzy, poznawaniu nowych technik i automatyzacji przestarzałych. Także i ja dbam o odwiedzających mój blog, a więc zamieszczam kolejny zbiór ciekawych i pouczających linków :-) Poniżej prezentuję kolejne darmowe artykuły i książki dla programistów, ciekawe odnośniki, mówiąc pokrótce – zasoby, [...]

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

Zend_Navigation jest pomocnym modułem Zend Framework, pozwalającym na prostą implementację menu oraz breadcrumbs na stronie opartej o ZF. Niestety nie jest to zbyt elastyczne narzędzie i nie pozwala “poszaleć”. Na szczęście mamy możliwość ingerencji w generowany kod HTML, a co za tym idzie, możemy dowolnie modyfikować sposób, w jaki Zend_Navigation generuje menu.

Na uwagę zasługują dwa rozwiązania. Każde z nich ma swoje wady i zalety i wybór któregoś z nich zależy wyłącznie od skomplikowania menu jakie mamy do stworzenia. W obu rozwiązaniach posłużę się następującym menu. Proszę zwrócić uwagę na niestandardowy element – image. Jest to ikonka, która wyświetli się zamiast etykiety. Brak tego elementu oznacza, że w menu wyświetli się tekst z elementu label.

Plik konfiguracyjny menu (application/configs/menu.php)

<?php
return array(
    array(
        'label' => 'Strona główna',
        'controller' => 'index',
        'action' => 'index',
        'image' => '/images/menu/home.png'
    ),
    array(
        'label' => 'O nas',
        'controller' => 'about',
        'action' => 'index'
    ),
    array(
        'label' => 'Kontakt',
        'controller' => 'contact',
        'action' => 'index'
    )
);

Metoda w pliku bootstrap.php

protected function _initNavigation()
{
	$this->bootstrap('view');
	$view = $this->getResource('view');
	$config = require APPLICATION_PATH . '/configs/menu.php';
	$navigation = new Zend_Navigation($config);
	$view->navigation($navigation);
}

Pierwsze rozwiązanie nie wymaga prawie żadnego wysiłku i sprowadza się do napisania prostego pliku z kodem HTML. Największą wadą takiego podejścia jest fakt, iż kolejne poziomy menu musimy sami oprogramować. Dlatego też najlepiej sprawdza się w przypadku prostych menu, gdzie mamy jeden lub określoną (niewielką) ilość poziomów. Użycie menu z przygotowanym plikiem wygląda następująco:

echo $this->navigation()->menu()->setPartial(array('menu.phtml', 'default'));

menu.phtml określa nazwę pliku jaki zostanie użyty do wyświetlenia menu, natomiast default określa w jakim module należy tego pliku szukać. Plik musi znajdować się w katalogu application/views/scripts. Przykładowa zawartość pliku menu.phtml

<ul>
	<?php foreach($this->container as $page): ?>
		<li<?php echo $page->isActive()?' class="active"':''; ?>>
			<a href="<?php echo $this->href; ?>">
				<?php if(isset($page->image)): ?>
					<img src="<?php echo $page->image; ?>"
						 alt="<?php echo $page->label; ?>" />
				<?php else: ?>
					<?php echo $page->label; ?>
				<?php endif; ?>
			</a>
		</li>
	<?php endforeach; ?>
</ul>

Do wszystkich elementów znajdujących się w menu możemy odwołać się poprzez właściwość obiektu $page. Niektóre właściwości, jak na przykład href, są zamieniane na metodę getHref. Możecie zajrzeć do klasy Zend_Navigation_Page oraz dziedziczących po niej Zend_Navigation_Page_Mvc oraz Zend_Navigation_Page_Uri w celu sprawdzenia jakie elementy i w jaki sposób można pobrać z obiektu $page.

Drugie podejście sprowadza się do napisania własnego helpera widoku, który dziedziczy po helperze Zend_View_Helper_Navigation_Menu oraz przesłania metodę htmlify, odpowiedzialną za wygenerowanie kodu HTML dla konkretnego elementu menu.

<?php
class Zend_View_Helper_ImgMenu extends Zend_View_Helper_Navigation_Menu
{
    public function imgMenu(Zend_Navigation_Container $container = null)
    {
        parent::menu($container);
        return $this;
    }

    public function htmlify(Zend_Navigation_Page $page)
    {
        // get label and title for translating
        $label = $page->getLabel();
        $title = $page->getTitle();

        // translate label and title?
        if ($this->getUseTranslator() && $t = $this->getTranslator()) {
            if (is_string($label) && !empty($label)) {
                $label = $t->translate($label);
            }
            if (is_string($title) && !empty($title)) {
                $title = $t->translate($title);
            }
        }

        // get attribs for element
        $attribs = array(
            'id'     => $page->getId(),
            'title'  => $title,
            'class'  => $page->getClass()
        );

        // does page have a href?
        if ($href = $page->getHref()) {
            $element = 'a';
            $attribs['href'] = $href;
            $attribs['target'] = $page->getTarget();
        } else {
            $element = 'span';
        }

        if(isset($page->image)) {
            $label = '<img src="' . $page->image . '" ?alt="' . $this- />view->escape($label) . '" . ?>';
        }
        else {
            $label = $this->view->escape($label);
        }

        return '<' . $element . $this->_htmlAttribs($attribs) . '>'
             . $label
             . '</' . ? $element>

Użycie menu z nowym helperem niczym się nie różni od użycia “zwykłego” menu. Zmienia się tylko nazwa helpera.

echo $this->navigation()->imgMenu();

Podejście drugie daje o wiele większe możliwości, ponieważ m.in. nie trzeba martwić się o kolejne poziomy menu – zadba o to Zend_Navigation. Wadą takiego podejścia jest potencjalne ryzyko zmiany helpera menu przez twórców frameworka.

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

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

Jednym z najczęstszych problemów związanych z Zend_Form jest brak możliwości dodawania kodu HTML między elementami formularza. Na szczęście Zend_Form jest na tyle rozbudowany, iż przy odrobinie pomysłowości wspomniany problem można dosyć łatwo obejść. Rozwiązań jest co najmniej kilka. Dzisiaj przedstawię dwa najprostsze.

Pierwszym rozwiązaniem jest zastosowanie opisu (description) w elemencie, po którym chcemy dodać kod HTML.

class Application_Form_Example1 extends Zend_Form
{
    public function init()
    {
        $this->setName('form-example1');

        $name = new Zend_Form_Element_Text('name');
        $name->setLabel('Nazwa');

        $email = new Zend_Form_Element_Text('email');
        $email->setLabel('E-mail')
              ->setDescription('<div id="some-id">lorem ippsum</div>');

        $phone = new Zend_Form_Element_Text('phone');
        $phone->setLabel('Telefon');

        $submit = new Zend_Form_Element_Submit('btn_save');
        $submit->setLabel('Zapisz');

        $this->addElement($name);
        $this->addElement($email);
        $this->addElement($phone);
        $this->addElement($submit);
    }
}

Kluczowym elementem powyższego kodu jest metoda setDescription, wywołana na obiekcie $email. Dzięki niej, do kodu formularza zostanie dodany kod HTML. Niestety kod zostanie wyświetlony w takiej formie, w jakiej został dodany – na stronie wyświetli się tekst

<div id="some-id">lorem ippsum</div>

Dzieje się tak dlatego, ponieważ kod HTML jest zamieniany na encje. Rozwiązaniem tego problemu jest ustawienie opcji escape dekoratora Description na false.

$email->addDecorator('Description', array('escape' => false));
Drugi sposób polega na zastosowaniu ukrytego elementu, w którym kod HTML wyświetlany jest w etykiecie.
class Application_Form_Example2 extends Zend_Form
{
    public function init()
    {
        $this->setName('form-example2');

        $name = new Zend_Form_Element_Text('name');
        $name->setLabel('Nazwa');

        $email = new Zend_Form_Element_Text('email');
        $email->setLabel('E-mail');

        $html = new Zend_Form_Element_Hidden('html');
        $html->setLabel('<div id="some-id">lorem ippsum</div>')
             ->setIgnore(true)
             ->addDecorator('Label', array('escape' => false));

        $phone = new Zend_Form_Element_Text('phone');
        $phone->setLabel('Telefon');

        $submit = new Zend_Form_Element_Submit('btn_save');
        $submit->setLabel('Zapisz');

        $this->addElement($name);
        $this->addElement($email);
        $this->addElement($html);
        $this->addElement($phone);
        $this->addElement($submit);
    }
}
Podobnie jak w przypadku opisu, etykieta również wymaga ustawienia opcji escape na false. Oczywistym jest, że podczas wysyłania formularza dodatkowe pole jest zbędne. Dzięki użyciu metody setIgnore, nadmiarowy element nie będzie występował w tablicy wartości przesłanych przez formularz.

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

Dawno temu obiecałem noose’owi napisać tutorial na temat tłumaczenia tras w Zend Frameworku. Niestety dopadła mnie masa odciągaczy uwagi i z tygodnia zrobiło się wiele tygodni. Udało mi się w końcu pozbyć niektórych odciągaczy i zbadać oraz opisać wspomniany temat.

Wszystko zaczyna się w pliku Bootstrap.php. Należy stworzyć w nim metodę, która doda do rejestru obiekt z tłumaczeniami. W przykładach posłużę się tłumaczeniami opartymi na tablicach, nic nie stoi na przeszkodzie, aby skorzystać z innego adaptera.

protected function _initTranslate()
{
    $translate = new Zend_Translate(
        'array',
        array(
            'users' => 'uzytkownicy',
            'list' => 'lista',
            'title' => 'tytul',
            'news' => 'aktualnosci',
	    // przykladowe tytuly artykulow
            'title1' => 'tytul1',
            'title2' => 'tytul2'
        ),
        'pl'
    );

    $translate->addTranslation(
        array(
            'users' => 'benutzer',
            'list' => 'liste',
            'title' => 'titel',
            'news' => 'nachrichten',
	    // przykladowe tytuly artykulow
            'title1' => 'titel1',
            'title2' => 'titel2'
        ),
        'de'
    );

    $translate->setLocale('de');

    Zend_Registry::set('Zend_Translate', $translate);
}

Powyższa metoda doda do aplikacji dwa języki – polski oraz niemiecki (jeśli pomyliłem jakiś wyraz, proszę o korektę) oraz ustawi domyślny język na polski. Na koniec do rejestru dodany zostanie obiekt z tłumaczeniem. Dzięki temu wszystkie “podatne na tłumaczenie” elementy Zend Frameworka będą mogły z niego skorzystać.

Ustawienie aktualnego języka nie musi odbywać w Bootstrapie. Można to zmienić później, np w pluginie.

$translate = Zend_Registry::get('Zend_Translate');
$translate->setLocale('de');

Jedyne co pozostało, to stworzenie odpowiednich tras, co również można wykonać w Bootstrapie. Do wyboru są trzy rodzaje tras: dynamiczna, statyczna oraz mieszana.

protected function _initRouting()
{
    $this->bootstrap('frontController');
    $front = $this->getResource('frontController');
    $router = $front->getRouter();

    $dynamicRoute = new Zend_Controller_Router_Route(
        ':@controller/:@action/*',
        array(
            'controller' => 'index',
            'action' => 'index'
        )
    );

    $staticRoute = new Zend_Controller_Router_Route(
        '@news',
        array(
            'controller' => 'news',
            'action' => 'index'
        )
    );

    $mixedRoute = new Zend_Controller_Router_Route(
        '@title/:@nazwa',
        array(
            'controller' => 'index',
            'action' => 'index',
            'nazwa' => ''
        )
    );

    $router->addRoute('dynamicRoute', $dynamicRoute);
    $router->addRoute('staticRoute', $staticRoute);
    $router->addRoute('mixedRoute', $mixedRoute);
}

Trasa dynamiczna to taka, która korzysta z dynamicznych segmentów, np kontrolera i/lub akcji (oraz modułu jeśli są wykorzystywane). Statyczna trasa zawiera jedynie statyczne elementy adresu, czyli takie, które wskazują na jeden konkretny zasób. Mieszana trasa daje możliwość skorzystać ze statycznego wskazania na konkretny zasób oraz dynamicznej zmiany innych segmentów adresu.

W każdym z wyżej wymienionych przypadków, kluczowym elementem jest symbol @, znajdujący się przed nazwą “zmiennej”. Informuje on router, iż należy skorzystać z tłumaczeń. Router pobiera tłumaczenie dla aktualnie ustawionego języka i zwraca je w tym właśnie języku.

Trasę można przetestować korzystając z helpera widoku url

echo $this->view->url(
    array(
        'controller' => 'users',
        'action' => 'list'
    ),
    'dynamicRoute'
);

echo $this->view->url(
    array(),
    'staticRoute'
);

echo $this->view->url(
    array('nazwa' => 'title1'),
    'mixedRoute'
);

echo $this->view->url(
    array('nazwa' => 'title2'),
    'mixedRoute'
);

Powyższy kod wyświetli dla języka polskiego

/uzytkownicy/lista
/aktualnosci
/tytul/tytul1
/tytul/tytul2

a dla niemieckiego

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

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

Wraz z dokumentacją Zend Frameworka, otrzymaliśmy zgrabnie napisany Quick Start. Dzięki niemu można w bardzo prosty sposób rozpocząć swoją przygodę z ZF. Pośród wszystkich dobrych rad jakich on udziela, jedna nie za bardzo przypadła mi do gustu – modele. Według przewodnika należy stworzyć trzy klasy, gdzie jedna jest modelem, druga odpowiada za dostęp do danych, a trzecia to mapper łączący dwie poprzednie. Podejście to nigdy mi się nie podobało, ponieważ wymagało ode mnie dodatkowego nakładu pracy, który tak naprawdę nie miał przełożenia na wygodę w późniejszym programowaniu. Dlatego też w moich projektach nie korzystam z mappera, a obiekt dostępu do danych inicjalizowałem w konstruktorze modelu.

Przez długi czas podejście to w zupełności mi wystarczało, jednak w przypadku dużych projektów powodowało sporo kłopotów. Każda, nawet najdrobniejsza zmiana w sposobie tworzenia obiektu dostępu do danych musi zostać wprowadzona we wszystkich klasach, korzystających z tego sposobu. Postanowiłem to zmienić. Pogrzebałem w manualu i znalazłem funkcję get_class. Dzięki niej jestem w stanie określić które “dziecko” utworzyło obiekt i na podstawie nazwy klasy, stworzyć właściwy obiekt dostępu db table.

Najlepszym wyjaśnieniem będzie kod. Oto on:

// klasa, po której dziedziczą modele
class App_Model
{
    /**
     * @var Zend_Db_Table_Abstract
     */
    protected $_dbTable = null;

    public function __construct()
    {
        $class = get_class($this);
        $classParts = explode('_', $class);
        $className = array_pop($classParts);
        array_push($classParts, 'DbTable', $className);
        $dbTableClassName = implode('_', $classParts);
        $this->_dbTable = new $dbTableClassName();
    }

    /**
     * @return Zend_Db_Table_Abstract
     */
    public function getDbTable()
    {
        if($this->_dbTable === null) {
            throw new Exception('There id no db table object');
        }
        return $this->_dbTable;
    }
}
// klasa modelu
class Application_Model_User extends App_Model
{
}
// klasa dostępu do danych
class Application_Model_DbTable_User extends Zend_Db_Table_Abstract
{
    protected $_name = 'users';
}

W momencie utworzenia obiektu Application_Model_User zostanie automatycznie stworzony obiekt Application_Model_DbTable_User.

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