Autor wpisu: Marek, dodany: 01.03.2012 19:58, tagi: zend_framework
Wygenerowany formularz z mojego poprzedniego wpisu wygląda tak:
<form enctype="multipart/form-data" method="post" action="/zf/test/public/index/rename"> <dl class="zend_form"> <dt id="newname-label"><label for="newname" class="optional">Zmień nazwę pliku:</label></dt> <dd id="newname-element"><input type="text" name="newname" id="newname" value=""></dd> <dt id="filename-label"><label for="filename" class="required">Plik:</label></dt> <dd> <input type="hidden" name="MAX_FILE_SIZE" value="8388608" id="MAX_FILE_SIZE"> <input type="file" name="filename" id="filename"> </dd> <dt id="submit-label"> </dt> <dd id="submit-element"> <input type="submit" name="submit" id="submit" value="Wyślij"></dd> </dl> </form>
Zend Framework podczas generowania formularzy stosuje domyślnie tagi dl, dd, dt. Ja jednak wolę przechowywać elementy formularza w tabeli. Poniżej przedstawiam kod, który chciałbym uzyskać:
<form enctype="multipart/form-data" method="post" action="/zf/test/public/index/rename"> <table> <tr> <th colspan="2">Wyślij plik</th> </tr> <tr> <td id="newname-label"><label for="newname">Zmień nazwę pliku:</label></td> <td><input type="text" name="newname" id="newname" value=""></td> </tr> <tr> <td id="filename-label"><label for="filename">Plik:</label></td> <td> <input type="hidden" name="MAX_FILE_SIZE" value="8388608" id="MAX_FILE_SIZE" /> <input type="file" name="filename" id="filename" /> </td> </tr> <tr> <td colspan="2"><input type="submit" name="submit" id="submit" value="Wyślij"></td> </tr> </table> </form>
Jak zatem wygenerować formularz w Zend Framework, tak aby jego elementy były zawarte w tabeli? Do tego oczywiście służą dekoratory.
Zmodyfikuję jeszcze tylko formularz dodając do niego opis:
$this->setDescription('Wyślij plik');
Po dodaniu elementów do formularza:
$this->addElements(array($newName, $file, $submit));
Ustawmy mu dekoratory:
// dekoratory formularza $this->setDecorators(array( array('Description', array('tag' => 'th', 'colspan' => 2)), array(array('tr' => 'HtmlTag'), array('tag' => 'tr')), 'FormElements', array('HtmlTag', array('tag' => 'table')), 'Form' ));
Nasz opis będzie znajdował się wewnątrz znaczników th. Po opisie zostaną wygenerowane elementy formularza, które razem z opisem zostaną zawarte w znaczniku table, a ten zostanie otoczony znacznikiem form.
Tutaj jedna uwaga. Dekoratory dodawane są do zmiennej tablicowej _decorators klasy formularza. A więc skoro raz używamy HtmlTag, będzie on użyty jako klucz w tablicy __decorators. Jeśli ponownie chcemy użyć tego samego dekoratora, musimy podać unikalny klucz (tutaj: array(‘tr’ => ‘HtmlTag’) )
Dalej ustawmy dekoratory kontrolek:
Autor wpisu: Marek, dodany: 01.03.2012 19:56, tagi: zend_framework
Aby wyłączyć renderowanie layoutu w kontrolerze wpisujemy:
$this->_helper->layout->disableLayout();
Metodę disableLayout znajdziemy w klasie Zend_Layout.
Aby wyłączyć renderowanie danego widoku w kontrolerze wpisujemy:
$this->_helper->viewRenderer->setNoRender();
Wywołujemy tutaj przy użyciu helpera metodę setNoRender() klasy Zend_Controller_Action_Helper_ViewRenderer
Autor wpisu: Marek, dodany: 01.03.2012 19:56, tagi: zend_framework
Poniżej przedstawiam maksymalnie uproszczony sposób przesyłania plików na serwer przy pomocy Zend Framework. Zakładam zapis pliku na serwerze, oraz zapis informacji o jego nazwie w bazie danych. Jest to pierwszy z serii artykułów – mam nadzieję, że w prosty sposób wprowadzi w to rozbudowane zagadnienie. A więc do dzieła.
Tworzymy bazę danych. Tutaj użyję SZBD SQLITE3. Bazę umieszczę w katalogu:
data/db/
i nazwę ją:
testfile.db
A więc z katalogu głównego aplikacji wykonujemy:
mkdir -p data/db
A potem:
sqlite3 testfile.db
W konsoli sqlite tworzymy tabelę files:
create table files ( id integer primary key autoincrement, filename varchar(150));
Gdzie w kolumnie „filename” będziemy przechowywać nazwę pliku. Teraz poinformujemy naszą aplikację o wybranym adapterze bazy danych i jej lokalizacji.
W pliku:
application/configs/application.ini
wpisujemy:
resources.db.adapter = "pdo_sqlite" resources.db.params.dbname = APPLICATION_PATH "/../data/db/testfile.db"
W pliku:
Autor wpisu: Marek, dodany: 01.03.2012 19:56, tagi: zend_framework
W poprzednim wpisie przedstawiłem podstawy przesyłania pliku na serwer przy pomocy Zend Framework. Czas zagłębić się bardziej w to zagadnienie.
Kolejnym przypadkiem, którym się zajmę jest rozbudowa formularza o pole tekstowe przechowujące opcjonalną nową nazwę dla wysyłanego pliku.
Skoro możemy zmienić nazwę pliku, użyty poprzednio walidator Zend_Validate_File_NotExists() już nie spełni swojej roli, bo możemy przesłać plik o takiej samej nazwie jak w katalogu docelowym, o ile podamy w formularzu nową nazwę (którą de facto musimy również zweryfikować).
A więc użyjemy własnego walidatora, który będzie dziedziczył po wcześniej wspomnianym, wprowadzając dodatkowe sprawdzanie dla nowej nazwy pliku. Walidator umieszczam w katalogu /library/My/Validate/File/
require_once 'Zend/Validate/File/NotExists.php'; class My_Validate_File_NotExists extends Zend_Validate_File_NotExists { /** * @var string nowa nazwa dla pliku */ protected $_newName = null; public function __construct($directory = array(), $newName = null) { $this->_newName = $newName; parent::__construct($directory); } public function isValid($value, $file = null) { // ustawienie nowej nazwy pliku, jeśli podana if (!empty($this->_newName)) { $fileName = isset($file['name']) ? $file['name'] : $value; $file['name'] = $this->_newName . '.' . pathinfo($fileName, PATHINFO_EXTENSION); } parent::isValid($value, $file); } }
Co tu się dzieje? Dzięki dziedziczeniu i w myśl zasady DRY nasz walidator jest bardzo prosty. W konstruktorze przekazujemy do niego nową nazwę pliku i wywołujemy konstruktor klasy rodzica. Metoda isValid() to serce naszej klasy. Sprawdzamy w niej czy została ustawiona nowa nazwa dla pliku. Jeśli tak, modyfikujemy nazwę przetrzymywaną w tablicy $file, dodając do niej rozszerzenie przesłanego pliku (które wyciągamy przy pomocy funkcji pathinfo()). Tak zmodyfikowane dane poddajemy walidacji klasy Zend_Validate_File_NotExists.
Przejdźmy do klasy formularza:
class Application_Form_Rename extends Zend_Form { public function init() { $this->setMethod('post'); $newName = new Zend_Form_Element_Text('newname'); $newName->setLabel('Zmień nazwę pliku:') ->addFilters(array('StringTrim', 'StripTags')); $file = new Zend_Form_Element_File('filename'); $file->addPrefixPath('My_Validate', '/My/Validate', 'validate') ->setLabel('Plik:') ->setRequired() ->setDestination(APPLICATION_PATH . '/../public/uploads') ->addValidator('Size', true, 1048576) ->addValidator('Extension', false, 'pdf'); $submit = new Zend_Form_Element_Submit('submit'); $submit->setLabel('Wyślij') ->setIgnore(true); $this->addElements(array($newName, $file, $submit)); } public function addRenameValidator($newName) { $destination = $this->filename->getDestination(); if (!empty($newName)) { $this->filename->addFilter('Rename', array( 'target' => $destination . DIRECTORY_SEPARATOR . $newName . '.' . pathinfo($this->filename->getFileName(), PATHINFO_EXTENSION), 'overwrite' => false)); } $this->filename->addValidator(new My_Validate_File_NotExists($destination, $newName)); }
}
W metodzie init(), inicjującej pola formularza, dodajemy obiekt Zend_Form_Element_Text, który będzie odpowiadał za kontrolkę nowej nazwy pliku. Dalej na obiekcie $file wywołujemy metodę addPrefixPath(), która pomoże później znaleźć klasę naszego walidatora. Kolejna metoda addRenameValidator() dodaje filtr Zend_Filter_File_Rename(), który zmieni nazwę przesyłanego pliku na nową (o ile ją podaliśmy). Dalej dodajemy do obiektu $filename walidator My_Validate_File_NotExists(), przekazując mu nową nazwę dla pliku.
Przyjrzyjmy się teraz kontrolerowi:
public function renameAction() { $form = new Application_Form_Rename(); $form->setAction($this->view->url()); if ($this->getRequest()->isPost()) { $data = $this->getRequest()->getPost(); $form->addRenameValidator($data['newname']); if ($form->isValid($data)) { if (!$form->filename->receive()) { //odbieramy plik throw new Zend_Exception('Wystąpił błąd przy odbieraniu pliku!'); } $db = new Application_Model_DbTable_File(); $db->insertRenamed($form->getValues()); $this->view->msg = 'Plik został pomyślnie zapisany'; } else { $this->view->msg = 'Wystąpił błąd!'; } } $this->view->form = $form; }
Akcja rename naszego kontrolera bardzo przypomina akcję index z poprzedniego wpisu. Z tym, że:
- przed sprawdzeniem poprawności danych przesłanych z formularza, wywołujemy metodę addRenameValidator(), podając jej nową nazwę pliku (co prowadzi do dodania wyżej opisanego walidatora)
- jeśli wystąpił błąd podczas odbierania pliku, wyrzucamy wyjątek
- jeśli plik został prawidłowo przesłany na serwer, zapisujemy dane do bazy
Został jeszcze model: