Peter Láng - Nullpointer.cz - RSS odběr Dexempo pro váš kód http://www.nullpointer.cz/ Webová aplikace v Nette pro začátečníky - DataTables - díl 4. Sun, 03 Feb 2013 22:20:53 GMT http://www.nullpointer.cz/webova-aplikace-v-nette-pro-zacatecniky-datatables-dil-4 <p>Dnes uděláme za naším seriálem malou tečku v podobě implementace šikovné jQuery tabulky DataTables. Ukážeme si na tom jak jednoduché je použití Ajaxu v Nette Frameworku.</p> <!-- by Texy2! --> <h2>DataTables</h2> <p>Poměrně často potřebujeme v aplikaci nějakou přehledovou tabulku s daty a potřebujeme tato data nějak řadit, filtrovat, hledat. Nette poskytuje podobné nástroje formou několika <a href="http://addons.nette.org/cs/#toc-datagridy">doplňků</a>, které doporučuji prostudovat a vyzkoušet, mimo jiné i proto, že ukazují ještě víc z toho, jak lze v Nette pracovat s ajaxem. My se dnes ale vydáme trochu jinou cestou – použijeme jQuery plugin, který poskytuje přinejmenším srovnatelné funkce.</p> <p>Plugin <a href="http://www.datatables.net/download">stáhneme</a> a vyzobneme si z něj soubory <code>jquery.dataTa­bles.min.js</code> a <code>jquery.dataTa­bles.css</code></p> <p>Soubory nakopírujeme do projektu a nalinkujeme standartním způsobem</p> <pre class="html"><code>&lt;head&gt; ... &lt;link rel="stylesheet" type="text/css" href="{$basePath}/css/jquery.dataTables.css" /&gt; ... &lt;script src="{$basePath}/js/jquery.dataTables.min.js"&gt;&lt;/script&gt; ... &lt;/head&gt;</code></pre> <h2>Šablona výpisu uživatelů</h2> <p>V šabloně výpisu uživatelů <code>Homepage/defau­lt.latte</code> máme odminule základní výpis uživatelů v seznamu. To nám už nebude stačit – DataTables plugin vyžaduje html tabulku ve zhruba tomto znění:</p> <pre class="html"><code>&lt;table id="users"&gt; &lt;thead&gt; &lt;th&gt;Jméno&lt;/th&gt; &lt;th&gt;Email&lt;/th&gt; &lt;th&gt;Role&lt;/th&gt; &lt;/thead&gt; &lt;tbody&gt;&lt;/tbody&gt; &lt;/table&gt;</code></pre> <p>Ze zápisu tabulky vyplývá, že jsme se rozhodli vypisovat jméno, email a roli uživatelů. Oživení a naplnění tabulky pomocí jQuery vypadá potom takto:</p> <pre class="js"><code>$('#users').dataTable( { "sAjaxSource": {link usersJson!}, "aoColumns": [ {"mData": "name"}, {"mData": "email"}, {"mData": "role"} ] });</code></pre> <p>Tímto kódem jsme řekli, že tabulka s id users bude plněna daty z adresy <code>{link usersJson!}</code>, což znamená, že framework bude hledat v presenteru, v kterém se právě nacházíme, metodu <code>handleUsersJson</code>. DataTables zároveň očekává, že mu z tohoto místa přijdou data v JSON formátu takovéto struktury:</p> <pre class="js"><code>{ "aaData": [ { "id": 9, "email": "franta@vokurka.cz", "name": "Franta Vokurka", "role": "guest" }, { "id": 10, "email": "lojza@lojza.cz", "name": "Lojza P\u0159echodn\u00edk", "role": "guest" }, }</code></pre> <p>Pomocí <code>„aoColumns“</code> potom definujeme, jaká data z JSON chceme zobrazovat v tabulce.</p> <p>Vyrobíme tedy požadovaný JSON – v (například) <code>HomepagePresen­ter.php</code> napíšeme metodu</p> <pre class="php"><code>public function handleUsersJson() { $all_users = array(); $all_users["aaData"] = $this-&gt;users-&gt;findAll()-&gt;orderBy('id')-&gt;fetchAll(); $this-&gt;sendResponse(new Nette\Application\Responses\JsonResponse($all_users)); }</code></pre> <p>Metoda si vyžádá z databáze všechny uživatele a jejich data a uloží je jako pole do proměnné <code>$all_users</code> pod klíč aaData. Tak to vyžaduje DataTables plugin. Data odešleme pomocí <code>$this-&gt;sendResponse</code> a <code>JsonResponse</code> ve formátu JSON.</p> <p>Na tomhle místě, kde poprvé posíláme data o uživatelích na frontend, bude potřeba upravit metodu <code>findAll()</code> v modelu Users, protože ve stávající podobě posílá do tabulky i hesla uživatelů. Sice zahashovaná, ale jak bychom vypadali, že? Úprava může vypadat třeba takto</p> <pre class="php"><code>public function findAll() { return $this-&gt;db-&gt;select('id, email, name, role')-&gt;from($this-&gt;table); }</code></pre> <p>Tak, a je to – <strong>hotovo</strong>.</p> <h2>Hotovo?</h2> <p>Máme co jsme chtěli a to, řekl bych, za dobrou cenu – máme tabulku, která umí data řadit ve sloupcích a umí hledat/filtrovat a řadit. To je ovšem pouze základní použití DataTables. K dispozici jsou rozšiřující <a href="http://www.datatables.net/extras/">pluginy</a>, jako například poměrně zásadní <a href="http://jquery-datatables-column-filter.googlecode.com/svn/trunk/index.html">columnFilter</a>.</p> <p>Data v tabulce také můžeme formátovat víceméně dle libosti. Například můžeme chtít z emailů udělat klikatelné odkazy – kód potom může vypadat třeba takto:</p> <pre class="javascript"><code>$('#users').dataTable( { "sAjaxSource": {link usersJson!}, "aoColumns": [ {"mData": "name"}, {"mData": "email", "fnRender": function(o) { return "&lt;a href='mailto:"+o.aData["email"]+"'&gt;"+o.aData["email"]+"&lt;/a&gt;"; } }, {"mData": "role"} ] });</code></pre> <h2>Závěr</h2> <p>Základní část seriálu je u konce. Ukázali jsme si na poměrně malém prostoru základní stavební kameny většiny webových aplikací – vkládání a čtení dat a jejich „chytré“ zobrazení. MacGyver by s tím dokázal vyrobit Facebook. Zdrojáky najdete na <a href="https://github.com/czlang/Users">githubu</a>.</p> <p>Mnoho (docela hodně) věcí jsme si naopak neukázali a zde jsou možnosti otevřené – buď je časem dopíšu jako volné pokračování na přání a/nebo odkážu. Podle komentářů z minulých dílů vybírám:</p> <h4>Testování</h4> <ul> <li>dokumentace Nette – <a href="http://doc.nette.org/cs/testing">Testování</a></li> <li><a href="http://pla.nette.org/cs/navstevni-kniha-a-testovani">Návštěvní kniha v Nette s testy (TDD)</a></li> <li><a href="http://filip-prochazka.com/blog/nette-tester-a-phpstorm">Nette/Tester a PhpStorm</a></li> <li><a href="http://blog.medio.cz/testovani-presenter">Testování presenterů v Nette</a></li> </ul> <h4>Composer</h4> <p>Správa závislostí v projektu</p> <ul> <li><a href="http://getcomposer.org/">http://getcomposer.org/</a></li> <li>dokumentace Nette – <a href="http://doc.nette.org/cs/composer">Composer</a></li> <li><a href="http://pla.nette.org/cs/sandbox-composer">Stažení sandboxu přes Composer</a></li> <li>Přednáška <a href="http://pla.nette.org/cs/posobota-38-filip-prochazka-composer">Filip Procházka: Představení nástroje Composer</a></li> </ul> <h4>Nette\Database</h4> <p>Alternativa k Dibi layeru</p> <ul> <li>dokumentace Nette – <a href="http://doc.nette.org/cs/database">Databáze &amp; ORM</a></li> <li><a href="http://pla.nette.org/cs/nette-database-vs-dibi">Nette\Database vs dibi</a></li> </ul> <p>A to je už opravdu vše, dotazy, opravy, doplnění, atakdále prosím do komentářů, díky a zase někdy příště.</p> http://www.nullpointer.cz/webova-aplikace-v-nette-pro-zacatecniky-datatables-dil-4 Nette - přihlašování a registrace uživatelů Thu, 27 Dec 2012 13:56:46 GMT http://www.nullpointer.cz/nette-prihlasovani-a-registrace-uzivatelu <p>V tomto díle seriálu se budeme věnovat přihlašování a registraci uživatelů.</p> <h2>Zdrojáky v Gitu</h2> <p>Pro lepší orientaci jsou nyní zdrojáky k <a href="https://github.com/czlang/Users">dispozici na GitHubu</a>. Díly mají svoje <a href="https://github.com/czlang/Users/tags">tagy</a>.</p> <h2>Registrace</h2> <p>Začneme od šablon – v souboru <code>app/templates/@la­yout.latte</code> změňte obsah mezi tagy <code>body</code>takto</p> <pre class="html"><code>&lt;script&gt; document.body.className+=' js' &lt;/script&gt; &lt;div id="header"&gt; &lt;h1&gt;&lt;a href="{plink Homepage:}"&gt;Uživatelé&lt;/a&gt;&lt;/h1&gt; &lt;/div&gt; &lt;div id="nav"&gt; &lt;a href="{plink Register:register}"&gt;Registrovat&lt;/a&gt; &lt;a href="{plink Sign:in}"&gt;Přihlásit&lt;/a&gt; &lt;/div&gt; &lt;div n:foreach="$flashes as $flash" class="flash {$flash-&gt;type}"&gt;{$flash-&gt;message}&lt;/div&gt; &lt;div id="content"&gt; {include #content} &lt;/div&gt;</code></pre> <p>V headeru jsme si vyrobili odkaz na homepage, aby se nám vždycky dobře vracelo domů. Vyrobili jsme taky odkazy na přihlášení a registraci.</p> <p>Odkaz ve tvaru <code>plink Register:register</code> znamená „utíkej do presenteru Register na metodu register“. <code>plink Homepage:</code> zase znamená „fofrem do presenteru Homepage na metodu default“, kterou tam nemusím psát, když se mi nechce, protože je <em>default</em>.</p> <p>Když si uložíme a mrkneme na výsledek v prohlížeči, vidíme, že odkaz na <em>Přihlásit</em> se tváří celkem normálně, kdežto odkaz na <em>Registrovat</em> je celý brunátný. Když ho prozkoumáme (firebugem, nebo něčím podobným), zjistíme, že <code>error: Cannot load presenter ‚Register‘, class ‚RegisterPresenter‘ was not found in '/var/www/User­s/app/presenter­s/RegisterPre­senter.php</code>.</p> <p>Znamená to jednoduše to, že se odkazujeme na presenter a metodu, která neexistuje. Naproti tomu odkaz Přihlásit volá presenter <code>SignPresenter</code> a metodu <code>renderIn</code> (nebo actionIn), jež jsou součástí sanboxu, který jsme v minulém díle stáhli.</p> <p>Podrobné info o <a href="http://doc09.nette.org/cs/generovani-odkazu">vytváření odkazů v dokumentaci</a>.</p> <p>Pojďme vytvořit v adresáři <code>app/presenters/</code> RegisterPresen­ter.php s tímto obsahem</p> <pre class="php"><code>&lt;?php class RegisterPresenter extends BasePresenter { protected function startup() { parent::startup(); } public function renderRegister(){ } }</code></pre> <p>Uložíme, mrkneme na výsledek a vidíme, že odkaz je už spokojený. Klikneme na něj a zase chyba (říkám tomu Exception Driven Development – můžu si to patentovat, nebo tady teď byl?). Chyba mluví jasnou řečí – musíme pro akci vytvořit šablonu.</p> <p>Vytvoříme v <code>app/templates/</code> adresář Register a soubor <code>register.latte</code> s obsahem</p> <pre class="html"><code>{block #content} &lt;h2&gt;Registrovat&lt;/h2&gt; {control registerForm}</code></pre> <p>Nevypadá to ale, posunuli jsme se. Nová exception říká, že neexistuje komponenta registračního formuláře registerForm, kterou voláme pomocí <code>{control registerForm}</code> v <code>register.latte</code>.</p> <p>Vytvořme proto <em>továrničku</em> <code>createComponen­tRegisterForm</code> v <code>app/presenter­s/RegisterPre­senter.php</code> která nám formulář vyrobí:</p> <pre class="php"><code>use Nette\Application\UI, Nette\Application\UI\Form as Form; class RegisterPresenter extends BasePresenter { /** @var Users */ private $users; protected function startup() { parent::startup(); $this-&gt;users = $this-&gt;context-&gt;users; } public function renderRegister(){ } protected function createComponentRegisterForm() { $form = new Form; $form-&gt;addText('name', 'Jméno'); $form-&gt;addText('email', 'E-mail: *', 35) -&gt;setEmptyValue('@') -&gt;addRule(Form::FILLED, 'Vyplňte Váš email') -&gt;addCondition(Form::FILLED) -&gt;addRule(Form::EMAIL, 'Neplatná emailová adresa'); $form-&gt;addPassword('password', 'Heslo: *', 20) -&gt;setOption('description', 'Alespoň 6 znaků') -&gt;addRule(Form::FILLED, 'Vyplňte Vaše heslo') -&gt;addRule(Form::MIN_LENGTH, 'Heslo musí mít alespoň %d znaků.', 6); $form-&gt;addPassword('password2', 'Heslo znovu: *', 20) -&gt;addConditionOn($form['password'], Form::VALID) -&gt;addRule(Form::FILLED, 'Heslo znovu') -&gt;addRule(Form::EQUAL, 'Hesla se neshodují.', $form['password']); $form-&gt;addSubmit('send', 'Registrovat'); $form-&gt;onSuccess[] = callback($this, 'registerFormSubmitted'); return $form; } }</code></pre> <p>Tím jsme vytvořili formulář i s validačními pravidly, která se budou kontrolovat na serveru i v klientovi. V klientovi proto, že v @layout.latte načítáme netteForms.js, který se o to postará. Podrobné info o <a href="http://doc.nette.org/cs/forms">tvorbě formulářů v dokumentaci</a>.</p> <p>Teď potřebujeme presenteru říct, co má dělat po vyplnění a odeslání formuláře. Formulář definuje metodu, kterou volá, v <code>$form-&gt;onSuccess[] = callback($this, ‚registerFormSub­mitted‘)</code>, tudíž ji napíšeme</p> <pre class="php"><code>public function registerFormSubmitted(UI\Form $form) { $values = $form-&gt;getValues(); $new_user_id = $this-&gt;users-&gt;register($values); if($new_user_id){ $this-&gt;flashMessage('Registrace se zdařila, jo!'); $this-&gt;redirect('Sign:in'); } }</code></pre> <p>Pomocí <code>$form-&gt;getValues()</code> jsme získali z formuláře data a vložili je do databáze. Pokud se podařilo, spravíme o úspěchu uživatele a přesměrujeme jej k přihlášení.</p> <p>Vložení nového uživatele provedeme, jak říká právě napsaná metoda, v modelu – konkrétně v <code>Users.php</code>:</p> <pre class="php"><code>public function register($data) { unset($data["password2"]); $data["role"] = "guest"; $data["password"] = sha1($data["password"] . self::$user_salt); return $this-&gt;db-&gt;insert($this-&gt;table, $data)-&gt;execute(dibi::IDENTIFIER); }</code></pre> <p>Z dat z formuláře jsme odstranili potvrzjící opakování hesla, uživateli přiřadili primitivním způsobem jakousi roli (prozatím stačí) a vyrobili heslo. Salt si dodáme například takto</p> <pre class="php"><code>class Users extends \Nette\Object { /** @var \DibiConnection */ private $db; private $table = "users"; public static $user_salt = "AEcx199opQ"; // třída pokračuje...</code></pre> <p>Než to vyzkoušíme, potřebujeme změnit databázi</p> <pre class="sql"><code>DROP TABLE IF EXISTS `users`; CREATE TABLE `users` ( `id` int(10) NOT NULL AUTO_INCREMENT, `email` varchar(50) NOT NULL, `password` char(60) NOT NULL, `name` varchar(100) NOT NULL, `role` varchar(100) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`email`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; INSERT INTO `users` (`id`, `email`, `password`, `name`, `role`) VALUES (1, 'franta@vokurka.cz', 'f63d757c919a7707aa6c0af5946fd24a28015779', 'Franta Vokurka', 'guest'), (2, 'lojza@lojza.cz', 'ebad7341ea91cf83593b0638817c16a563bd4037', 'Lojza Přechodník', 'guest'), (3, 'mala@tonicka.cz', 'e1822661e05f4595d4ccaf4c8cd5b7f997a5e82c', 'Tonička Malá', 'guest'), (4, 'gerda@zapasnikova.cz', '51fcf163696a95f0674f123509a469092fc2d34e', 'Gerda Zápasníková', 'guest'), (5, 'anna@k.cz', '1ec2131552f3bd668591b0b99407b23355ba1ebc', 'Anna Kareninová', 'guest'), (6, 'barca@bramburka.cz', 'f04003366fb2f36149d392b547a7440d778046d7', 'Barbora Brambora', 'guest'), (7, 'hilda@zelena.cz', 'e08c606ff2fbc1a1991febf00b0fa8721d7d09ca', 'Hilda Zelená', 'guest'), (8, 'hajdy@zhor.cz', '626a453385ad62ad723655f706a2993eeb5c2922', 'Hajdy Zhor', 'guest'), (9, 'johanka@vplutu.com', '2b49d3bf378036984695dfd2a96bee427627e87d', 'Johanka Tazpluta', 'guest');</code></pre> <p>Hotovo, vyzkoušejte a běda jak to nebude fungovat.</p> <h2>Přihlášení</h2> <p>Registrace vám bezvadně funguje, přihlášení se ale nezdaří, protože k přihlášení používáme „vestavěný“ <code>app/model/Authen­ticator.php</code> a ten jsme vůbec neupravili pro práci s naší databází. Smažte obsah třídy a nahraďte jej za toto</p> <pre class="php"><code>use Nette\Security as NS; /** * Users authenticator. * * @author John Doe * @package MyApplication */ class Authenticator extends Nette\Object implements NS\IAuthenticator { /** @var \DibiConnection */ private $db; private $table = "users"; public function __construct(\DibiConnection $connection) { $this-&gt;db = $connection; } /** * Performs an authentication * @param array * @return Nette\Security\Identity * @throws Nette\Security\AuthenticationException */ public function authenticate(array $credentials) { list($username, $password) = $credentials; $row = $this-&gt;db-&gt;select('*')-&gt;from($this-&gt;table)-&gt;where('email = %s', $username)-&gt;fetch(); if (!$row) { throw new NS\AuthenticationException("User '$username' not found.", self::IDENTITY_NOT_FOUND); } if ($row-&gt;password !== sha1($password . Users::$user_salt)) { throw new NS\AuthenticationException("Invalid password.", self::INVALID_CREDENTIAL); } unset($row-&gt;password); return new NS\Identity($row-&gt;id, $row-&gt;role, $row-&gt;toArray()); } }</code></pre> <p>Třídě jsme dodali připojení k databázi a ukázali tabulku z které brát data. Taky jsme v metodě <code>authenticate</code> řekli, že pokud najde uživatele s emailem a heslem shodným s tím co přišlo z formuláře, má vrátit jeho <code>NS\Identity</code>.</p> <p>Nyní již máte všechny potřebné indicie k tomu se zaregistrovat i přihlásit. Gratulki.</p> <h2>Shrnutí, příště</h2> <p>Na to, že článek měl být bleskovým výcucem toho nejnutnějšího, je i tak dost dlouhý, takže pro další (důležité) info prosím račte navštívit ctěnou dokumentaci – <a href="http://doc.nette.org/cs/security">Přihlašování &amp; oprávnění uživatelů</a>.</p> <p>Příště bychom se možná konečně mohli dostat k „napojení“ <a href="http://datatables.net/examples/">Datatables</a> – ačkoliv se to tváří jako zlatý hřeb seriálu, uvidíte, že se jedná o v podstatě triviální kratochvíli.</p> http://www.nullpointer.cz/nette-prihlasovani-a-registrace-uzivatelu Webová aplikace v Nette pro začátečníky - 2.díl Sun, 16 Dec 2012 16:37:43 GMT http://www.nullpointer.cz/webova-aplikace-v-nette-pro-zacatecniky-2-dil <p>V tomto díle seriálu si, jak <a href="http://www.nullpointer.cz/webova-aplikace-v-nette-pro-zacatecniky-uvod">jsem minule slíbil</a>, nastavíme prostředí pro práci, rozjedeme Nette a Dibi a pozdravíme svět.</p> <h2>PHP a MySQL</h2> <p>Budeme samozřejmě pracovat v lokálním vývojovém prostředí, takže budeme potřebovat rozjet lokální server s PHP a MySQL.</p> <p>Uděláme to tím nejjednodušším způsobem – pro windows existuje několik instalačních „balíků“, které řeší většinu toho, co Běžný Franta Vývojář potřebuje.</p> <p>Jsou to například:</p> <ul> <li><a href="http://www.apachefriends.org/en/xampp.html">XAMPP</a></li> <li><a href="http://www.wampserver.com/en/">WampServer</a></li> <li><a href="http://www.easyphp.org/">EasyPHP</a></li> </ul> <p>V tomto seriálu použiju poslední jmenovaný – ze stránek EasyPHP si <a href="http://www.easyphp.org/save-easyphp-latest.php">stáhněte instalační soubor</a> a spusťte jej. Proklikejte se instalací, není v ní nic záludného. Po úspěšném skončení instalace byste měli v prohlížeči na adrese <a href="http://127.0.0.1/">http://127.0.0.1/</a> vidět rozhraní EasyPHP se seznamem projektů.</p> <p>EasyPHP si ve výchozím nastavení pro tyto projekty sahá do umístění <code>&lt;disk&gt;/Program Files/EasyPHP-&lt;verze&gt;/www</code>, zde vytvořte soubor info.php s obsahem</p> <pre class="php"><code>&lt;?php phpinfo();</code></pre> <p>V rozhraní EasyPHP v prohlížeči by se měl soubor info.php objevit – klinkěte na něj a v případě, že všechno funguje, se pokochejte konfigurací PHP.</p> <p>Pro správu MySQL databáze použijeme Adminer, který si <a href="http://www.adminer.org/#download">stáhněte</a> a stažený soubor umístěte na stejnou úroveň vedle souboru info.php. Klikněte na něj v rozhraní EasyPHP, jako uživatele zadejte root a přihlaste se. Uvidíte seznam databází, ty nás ale nezajímají, vytvoříme si pro náš projekt databázi novou :</p> <pre class="mysql"><code>CREATE DATABASE `users` COLLATE 'utf8_bin';</code></pre> <p>V této fázi, pokud vše proběhlo bez problému, máme nainstalové PHP a MySQL a vytvořenou prázdnou databázi. Pojďme na Nette a Dibi.</p> <h2>Nette Framework</h2> <p><a href="http://nette.org/cs/download">Stáhněte si Nette</a>. V seriálu budu používat Nette pro PHP 5.3 a vyšší, bez prefixů, <a href="http://files.nette.org/releases/2.0/">verzi 2.0.6</a>. Po stažení rozbalte zip a najděte v adresáři tools nástroj zvaný Requirements-Checker, který nakopírujte do EasyPHP www adresáře a spusťte v prohlížeči. Tento nástroj zkontroluje, zda je náš vývojový server způsobilý pro fungování s Nette, což je, takže můžeme směle pokračovat.</p> <p>Vedle adresáře tools v Nette balíku se nachází adresář <strong>sandbox</strong>, což je taková (skoro) minimální fungující předpřipravená Nette webová stránka. Nakopírujte celý sandbox do EasyPHP adresáře a spusťte v prohlížeči. Uvidíte uvítací projekt Nette, na kterém postavíme naši aplikaci.</p> <p>Pro další informace o instalaci a struktuře Nette vřele doporučuji <a href="http://doc.nette.org/cs/installation">Stažení a instalace v dokumentaci</a></p> <h2>Netbeans</h2> <p>Přicházíme do fáze, ve které budeme potřebovat nějaký editor. Ten je vždy otázkou osobní volby, já budu v tomto seriálu budu používat Netbeans. <a href="http://netbeans.org/downloads/">Stáhněte si Netbeans pro PHP</a>, nainstalujte a spusťte. Vytvoříme si nový projekt Users a to importem adresáře sandbox. Nejdříve si na disku přejmenujte adresář sandbox na Users a potom v Netbeans proveďte <code>File → New Project → PHP / PHP Application with existing sources → Vyberte &lt;adresar_projek­tu_na_disku&gt; a Finish.</code></p> <p>Do Netbeans si ještě nastavíme <a href="http://xdebug.org/">Xdebug</a> na krokování programem, ale to až někdy příště.</p> <h2>Dibi a databáze</h2> <p><a href="http://dibiphp.com/cs/">Dibi</a> je knihovna pro práci s databází. <a href="http://dibiphp.com/cs/download">Stáhněte si verzi 2.0.1</a>, rozbalte a vnitřní adresář <code>dibi</code> (obsahuje adresáře drivers, libs, Nette a soubour dibi.php) nakopírujte do našeho projektu do adresáře libs. Smažte obsah adresáře temp/cache a refreshněte projekt v prohlížeči – Nette loader se tak postará o „natáhnutí“ Dibi do projektu.</p> <p>Konfigurace Nette projektu probíhá v <code>&lt;projekt&gt;/app/con­fig/config.ne­on</code> a v <code>&lt;projekt&gt;/app/bo­otstrap.php</code>. V těchto místech si teď nastavíme Dibi.</p> <p>Otevřete si soubor a do config.neon pod řádek <code>development &lt; common</code> vložte</p> <pre><code>development &lt; common: dibi: host: localhost username: root password: database: users lazy: TRUE</code></pre> <p>Co jsme právě udělali – do „sekce“ <em>development</em> která je podmnožinou sekce <em>common</em>, jsme zapsali konfiguraci připojení k databázi pro vývojové prostředí. Pro nasazení na ostrý server bychom zadali konfiguraci do sekce <code>production &lt; common </code>. Nette pak automaticky rozliší v jakém prostředí se nachází. Jak je zřejmé, konfigurace platící pro všechna prostředí umístíme do sekce <code>common</code></p> <p>Při zapisování konfigurace si dávejte dobrý pozor, abyste odsazovali buď pomocí mezer, nebo skutečných tabulátorů, nikdy ne obojí zároveň – <a href="http://doc.nette.org/cs/configuring#toc-konfigurace-v-neon-souboru">více o konfiguraci v config.neon Nette v dokumentaci</a>.</p> <p>Pokračujeme v souboru <code>bootstrap.php</code>, kde Dibi zaregistrujeme pomocí rozšíření, které ve verzi 2 obsahuje. Před vytvořením <acronym title="Dependency Injection">DI</acronym> kontejneru pomocí</p> <pre class="php"><code>$container = $configurator-&gt;createContainer();</code></pre> <p>řekneme, že</p> <pre class="php"><code>$configurator-&gt;onCompile[] = function ($configurator, $compiler) { $compiler-&gt;addExtension('dibi', new DibiNetteExtension); };</code></pre> <p>Tím jsme s konfigurací Dibi hotovi. Nebo ne? Zkusíme to ověřit.</p> <h2>Model a práce s daty</h2> <p>Jak je v <acronym title="Model-View-Controller">MVC</acronym> kraji zvykem, do databáze se podíváme skrze model. V adresáři <code>app/model</code> vytvořte soubor <code>Users.php</code> s obsahem</p> <pre class="php"><code>class Users extends \Nette\Object { /** @var \DibiConnection */ private $db; private $table = "users"; public function __construct(\DibiConnection $connection) { $this-&gt;db = $connection; } public function findAll() { return $this-&gt;db-&gt;select('*')-&gt;from($this-&gt;table); } }</code></pre> <p>Zde myslím vše jasné – v konstruktoru jsme si dodali Dibi připojení a napsali si metodu <code>findAll</code>, která vrátí obsah tabulky <code>users</code>. Pokračujeme do další vrsty a to <code>app/presenter­s/HomepagePre­senter.php</code></p> <pre class="php"><code>class HomepagePresenter extends BasePresenter { /** @var Users */ private $users; protected function startup() { parent::startup(); $this-&gt;users = $this-&gt;context-&gt;users; } public function renderDefault() { $this-&gt;template-&gt;anyVariable = 'any value'; } }</code></pre> <p>Zde se naopak děje cosi na první pohled trochu zvláštního – kde se vzalo a co to je <code>$this-&gt;context-&gt;users</code> v metodě <code>startup</code>? Uložte všechny změny a zkuste reload projektu v prohlížeči. To co vidíte je váš přítel – <a href="http://doc.nette.org/cs/debugging#toc-vizualizace-chyb-a-vyjimek">ladící výpis Nette</a>, neboli takzvaná „Laděnka“.</p> <p>Podstatné je sdělení <em>Service ‚users‘ not found</em>. To je to <code>users</code>, které požadujeme v startup metodě. Pojďme do <code>config.neon</code> dodělat, co jsme začali – do common sekce pod definice services zadejte</p> <pre><code>services: users: class: \Users(@dibi.connection)</code></pre> <p>Tím by měla být konfigurace Dibi a profouknutí Modelu hotova. Ověříme to výpisem dat.</p> <h2>Výpis dat</h2> <p>V databázi vytvořte tabulku users</p> <pre class="sql"><code>CREATE TABLE `users` ( `id` int(10) NOT NULL AUTO_INCREMENT, `email` varchar(50) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`email`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; INSERT INTO `users` (`id`, `email`) VALUES (1, 'hello@world.cz'), (2, 'lojza@lojza.cz'), (3, 'mala@tonicka.cz'), (4, 'gerda@zapasnikova.cz'), (5, 'anna@k.cz'), (6, 'barca@bramburka.cz'), (7, 'hilda@zelena.cz'), (8, 'hajdy@zhor.cz'), (9, 'johanka@vplutu.com');</code></pre> <p>Blížíme se do finále, vypíšeme si naše skvostné uživatele a dáme si čaj.</p> <p>V <code>HomepagePre­senter.php</code> změňte metodu <code>renderDefault</code>, která obsluhuje domácí stránku, takto</p> <pre class="php"><code>public function renderDefault() { $all_users = $this-&gt;users-&gt;findAll()-&gt;orderBy('id')-&gt;fetchAll(); $this-&gt;template-&gt;all_users = $all_users; }</code></pre> <p>Zde je vše jasné – do šablony jsme si poslali všechny uživatele seřazené podle jejich id.</p> <p>V šabloně domácí stránky je jednoduše vypíšeme – obsah <code>app/templates/Ho­mepage/default­.latte</code> změňte na</p> <pre><code>{block content} &lt;ul&gt; {foreach $all_users as $user} &lt;li&gt;{$user-&gt;email}&lt;/li&gt; {/foreach} &lt;/ul&gt;</code></pre> <p>a pokochejte se výsledkem v prohlížeči.</p> <h2>Shrnutí</h2> <p>Pro začátek máme hotovo – máme nastaveny základní nástroje pro další práci, umíme si vypsat obsah MySQL tabulky do šablony. Mnoho věcí jsem v zájmu kompaktnosti článku vynechal/nazna­čil/zestručnil – případné nejasnosti doporučuji zatím buď neřešit, nebo vyhledat v <a href="http://doc.nette.org/cs/">dokumentaci Nette</a>, nebo na <a href="http://forum.nette.org/cs/">fóru Nette</a>.</p> <p>Samozřejmě, pokud je v článku něco nesrozumitelného, nebo je tam vyložená chyba, komentáře jsou vám k dispozici.</p> <h2>Příště</h2> <p>V příštím díle si do aplikace napíšeme obsluhu pro registraci a přihlašování uživatelů. Což bude brnkačka.</p> http://www.nullpointer.cz/webova-aplikace-v-nette-pro-zacatecniky-2-dil Webová aplikace v Nette pro začátečníky - úvod Wed, 28 Nov 2012 17:39:58 GMT http://www.nullpointer.cz/webova-aplikace-v-nette-pro-zacatecniky-uvod <h2>Co by měl seriál přinést?</h2> <p>Výsledkem seriálu bude fungl nová aplikace, která bude umět registrovat, přihlásit a spravovat uživatele. Kromě <a href="http://nette.org/">Nette</a> použijeme <a href="http://dibiphp.com/">Dibi</a> pro práci s MySQL a jQuery přinejmenším pro šikovnou tabulku s údaji uživatelů.</p> <p>Dalším potenciálně zajímavým prvkem seriálu, by také mohlo být srovnání s vývojem téměř stejné aplikace v úplně jiném prostředí, v sousedském seriálu <a href="http://www.nullpointer.cz/serial/webova-aplikace-v-jave-od-a-do-z">Webová aplikace v Javě od A do Z</a>.</p> <h2>Je to pro vás?</h2> <p>Pokud dodnes píšete v „čistém“ PHP a žádný framework jste dosud nezkusili (neboť jste přicestovali strojem času z minulosti) pak se domnívám že ano. Pokud píšete aplikace v jiném frameworku může to být pro vás zajímavé srovnání. Jestli v Nette píšete jednu složitější aplikaci za druhou, pak se nejspíš nic moc nového nedozvíte (ale zase mě můžete opravovat v komentářích).</p> <h2>Co potřebujete znát?</h2> <p>V seriálu se <strong>ne</strong>budu zabývat vysvětlováním PHP, MySQL ani Javascriptu. Naopak se pokusím ukázat fungování Nette, Dibi a některých pluginů jQuery (např. Datatables).</p> <h2>Použité technologie</h2> <ul> <li>lokální Apache server s PHP 5 a MySQL</li> <li><a href="http://netbeans.org/">IDE Netbeans</a></li> <li><a href="http://nette.org/">Nette Framework</a></li> <li><a href="http://dibiphp.com/">Dibi Database Layer pro práci s MySQL</a></li> <li><a href="http://jquery.com/">jQuery</a></li> </ul> <p>V příštím pokračování seriálu se už konečně pustíme do díla – nastavíme si prostředí pro práci, rozjedeme Nette a Dibi a pozdravíme svět!</p> http://www.nullpointer.cz/webova-aplikace-v-nette-pro-zacatecniky-uvod Texyla editor a fullscreen mód Sun, 14 Oct 2012 20:41:43 GMT http://www.nullpointer.cz/texyla-editor-a-fullscreen-mod <p>Texyla editor je, jak praví <a href="https://github.com/janmarek/Texyla/wiki">oficiální stránky</a>, „javascriptový modulární přizpůsobitelný non-wysiwyg editor obsahu webových stránek specializovaný na Texy! syntaxi.“ Používáme ho i tady na Nullpointer.cz a chyběla nám funkce fullscreen editace obsahu. Ve výchozí verzi Texyla tuto možnost nenabízí, nezbývá tedy, než si ji dodělat.</p> <p>V ideálním případě by výsledkem takového snažení měl být kód, který můžu poslat jako pull request autorovi texyly a ten by ji mohl začlenit do projektu. Texyla má dokonce přesně takovou <a href="https://github.com/janmarek/Texyla/issues/9">issue</a> (postarší). V takovém stadiu nicméně moje řešení není, v duchu sloganu tohoto webu jde zatím spíše o to <strong>dexempo</strong>. Dost řečí, jdeme na věc.</p> <h3>Vytvoření nového tlačítka</h3> <p>Texyla podporuje, alespoň podle <a href="https://github.com/janmarek/Texyla/wiki/API-pro-tvorbu-plugin%C5%AF">dokumentace</a>, jednoduchý způsob jak přidat tlačítko do menu editoru a to nějak takto…</p> <pre class="js"><code>$.texyla.addButton("fullscreen", function () { // our new button magic here });</code></pre> <p>… s tím, že tlačítko <em>zaregistrujeme</em> do definice Texyly například tímto způsobem…</p> <pre class="js"><code>$("#frmpostForm-body").texyla({ toolbar: [ 'h1', 'h2', 'h3', 'h4', null, "fullscreen" ], });</code></pre> <p>… vytvoříme jazykový překlad – zatím stačí česky – do souboru <code>cs.js</code> přidáme …</p> <pre class="js"><code>btn_fullscreen: "Fullscreen editor",</code></pre> <p>… a nahrajeme tlačítku do adresáře <code>texyla/icons</code> nějakou tu ikonku.</p> <h3>Tlačí to?</h3> <p>V této fázi máme <strong>nové tlačítko</strong> a <strong>taky nový problém</strong>. Tlačítko totiž po stisknutí vyhazuje okno s varováním <em>Function „fullscreen“ is not supported!</em>. Což mi tak na hodinku dvě docela smotalo vousy. Long story short, jak se říká u nás, řešení jsem našel metodou <em>pokus-omyl-díky Bohu</em> a nachází se v souboru <code>texyla.js</code> uvnitř</p> <pre class="js"><code>Texyla.prototype.buttons={</code></pre> <p>Sem je třeba přidat:</p> <pre class="js"><code>fullscreen:function(){}</code></pre> <p>Tím máme v podstatě vyhráno, zbývá už jen našemu novému tlačítku dát nějaký smysluplný obsah. V mém případě zatím dělá práci zhruba toto:</p> <pre class="js"><code>$.texyla.addButton("fullscreen", function () { var isFullscreen = $('.texyla').hasClass('texyla-fullscreen'); if(isFullscreen){ $(".texyla").attr("style", "width: 832px;"); $("#frmpostForm-body").attr("style", ""); $(".ui-wrapper").attr("style", "height:100%;"); $(".texyla").removeClass("texyla-fullscreen"); } else{ $(".texyla").attr("style", ""); $(".preview-wrapper").attr("style", ""); $("#frmpostForm-body").attr("style", ""); $(".ui-wrapper").attr("style", "height:100%;"); $(".texyla textarea").attr("style", "width: 100%;height:100% !important;"); $(".texyla").addClass("texyla-fullscreen"); } });</code></pre> <h3>Vytlačeno jest</h3> <p>A to je prozatím myslím vše, jestli se mi časem podaří udělat rozšíření přímo do Texyly, dám vědět. Pokud tento článek někdo vezme jako odrazový můstek pro totéž, taky dobře.</p> http://www.nullpointer.cz/texyla-editor-a-fullscreen-mod Tooltip ve SlickGrid tabulce Fri, 12 Oct 2012 13:14:19 GMT http://www.nullpointer.cz/tooltip-ve-slickgrid-tabulce <p>Potřeba mít <strong>v tabulce</strong> nějaký druh <strong>tooltip</strong> nápovědy je celkem běžná. Dnes si ukážeme jak poměrně jednoduše zprovoznit takovou nápovědu v jQuery tabulce, konkrétně <a href="https://github.com/mleibman/SlickGrid/wiki/Examples">SlickGrid</a>.</p> <h3>Definice tabulky</h3> <p>Nejdřív si nějakou tu jednoduchou SlickGrid tabulku nadefinujeme, třeba nějak takhle</p> <pre class="html"><code>&lt;div id="myGrid" style="width:350px;min-height:300px; margin: 30px 0 0 30px;"&gt;&lt;/div&gt;</code></pre> <pre class="js"><code>var dataView; var grid; var mydata = "[{\"id\": \"id_1\", \"realId\": \"26050\", \"label\": \"Test\" }, {\"id\": \"id_2\", \"realId\": \"26054\", \"label\": \"Test 2\"}]"; var data = jQuery.parseJSON(mydata); var columns = [ {id: "nazev", width: 350, name: "Nazev", field: "label"} ]; $(function () { dataView = new Slick.Data.DataView({ inlineFilters: true }); dataView.setItems(data); grid = new Slick.Grid("#myGrid", dataView, columns); })</code></pre> <p>Abychom zobrazili tooltip, potřebujeme nějak pracovat s daty ve sloupcích, nějak je formátovat, a na to máme – počkejte si na to – <strong>formattery</strong>! Formatter je funkce, která nám data v tabulce <em>přechroustá</em> podle potřeb. Pojďme jeden přidat:</p> <pre class="js"><code>var TaskNameFormatter = function (row, cell, value, columnDef, dataContext) { value = value + "&lt;span class='tooltip' id='tooltip"+dataContext["realId"]+"' style='display: none;'&gt;"+value+" tooltip !&lt;/span&gt;" return value; };</code></pre> <p>Tahle funkce udělá to, že za každou hodnotu v řádku tabulky přidá další schovaný řádek s nějakou hodnotou. Bystřejší už uhodli – tentýž řádek na konci zázračně <em>odschováme</em> a vykouzlíme tak náš tooltip.</p> <p>Funkci ale musíme nějak někde zavolat a proto upravíme kód takto:</p> <pre class="js"><code>var columns = [ {id: "nazev", width: 350, name: "Nazev", field: "label", formatter: TaskNameFormatter} ];</code></pre> <p>Tím jsme změnili definici tabulky a v kódu v prohlížeči by už měly být vidět schované položky.</p> <p>Zbývají už jen dvě věci: zjistit jak aktivovat naše <em>odschovávátko</em> na hover událost a poplácat se po rameni. SlickGrid na to má konkrétně tento nástroj:</p> <pre class="js"><code>grid.onMouseEnter.subscribe(function(e, args) { var cell = grid.getCellFromEvent(e) var row = cell.row var item = dataView.getItem(row); $("#tooltip"+item.realId+"").stop().show('fast'); });</code></pre> <p>Kód mluví jasnou řečí: na objektu grid jsme při hoveru myší ukázali prvek, který jsme předtím vytvořili a schovali. A protože všechno se omrzí, necháme ho po odjetí myší zase pěkně zmizet:</p> <pre class="js"><code>grid.onMouseLeave.subscribe(function(e, args) { var cell = grid.getCellFromEvent(e) var row = cell.row var item = dataView.getItem(row); $("#tooltip"+item.realId+"").stop().hide('fast'); });</code></pre> <h3>Slovo na závěr</h3> <p>Tak a to je vše – <a href="https://gist.github.com/3879250">kompletní funkční kód</a> pro ty, kterým se nepodařilo poslepovat.</p> <p>Řešení je to takové nanicovaté, protože schovaný tooltip vypisujeme do kódu pro všechny řádky. V případě textu to nemusí tak vadit, ale například já budu potřebovat zobrazovat obrázky a to se pro velký počet řádků prodraží. Zřejmě budu muset tahat data ajaxem až na požádání, nebo něco v tom smyslu.</p> <p>Taky vyvstává problém kde přesně tooltip zobrazovat, tabulka totiž zatvrzele odmítá respektovat existenci čehokoliv mimo svůj rámec, ale to už je na hrátky s CSS. Ani samotná SlickGrid komponenta se mi nakonec moc nelíbí, ale lepší zatím nemám.</p> <p>Děkuji za pozornost a u našeho pořadu opět příště zdarec.</p> http://www.nullpointer.cz/tooltip-ve-slickgrid-tabulce