NanoCMS – Nette example dynamického webu
- Droid
- Člen | 92
Dobrý den, lidé Nette hodně vytýkají, že nemá víc opensource projektů a hlavně nějaké jednoduché cms, na kterém by se dalo stavět. Možná neznám Nette „best practices“, ale rozhodně mám snahu to zlepšit a pomoct nováčkům při rozkoukávání v Nette. Vytvořil jsem tedy NanoCMS – opravdu nejprimitivnější CMS, které se v aktuální fázi hodí spíš jako example na prostudování, než jako CMS, na kterém by se dalo stavět. Do budoucna bych to chtěl ale určitě změnit, možná třeba někoho z Vás tohle nakopne (o to mi nepřímo jde) a něco začne psát nebo spolupracovat.
Obecné info:
- Nette\Database
- Front a Admin modul
- výchozí stránka je první záznam z databáze
- Flash zprávičky po pár vteřinách mizí
- Ošetřena duplicita URL (slugu)
- Přidán kontaktní formulář
- KISS ModelLoader za pomocí DI
- Lepší rozvržení presenterů a modelů
Demo webu: http://www.gnip.cz/nanocms3/www/ (nová verze)
Demo administrace: http://www.gnip.cz/…s3/www/admin
Download: http://www.gnip.cz/…/nanocms.zip
Github: https://github.com/Ginny/NanoCMS (stará verze)
Bylo by fajn poslat pull request nebo mne upozornit sem do vlákna na
nějakou „prasárnu“, chybu nebo vychytávku. Aktuálně je tam potřeba
dodělat pár drobností.
Inspirace: Davidovo CD-Collection, Modules usage, HosipLanův post (https://forum.nette.org/…dnot-pri-mvc#…
bych chtěl všem mockrát poděkovat :-)
Editoval Droid (29. 8. 2012 13:15)
- Filip Procházka
- Moderator | 4668
Jak na to tak koukám, tak když jsi opravil to co jsem v rychlosti napsal do fóra, tak už moc toho psaní nebylo co? :)
Každopádně dobrá práce, začátečníkům se to bude hodit :)
Na čem zapracuj, co je nejdůležitější, tak pojmenování tříd a
metod. Třída Model
určitě není pojmenovaná zrovna
nejšťastněji.
- Patrik Votoček
- Člen | 2221
Super!
Jen bych možná přidal políčko na editaci slugu a na homepage odkaz do adminu (někomu nemusí být jasné že to je http://example.com/admin)
- bojovyletoun
- Člen | 667
Je to určitě přínosný příklad.
Nápady, co bych vylepšil(vzhledem k minimalističnosti to jsou detaily):
- Přidal bych tam texylu a texy(jako service).
- Moc se mi nelíbí třída model, je to takový hegemon. Měl bych nápad, ale rozepíšu ho až jindy.
- zrušil bych Environment
- Selector už nemá find()
'slug' => $first_page->slug
podle mě nemá v bootstrapu a routeru co dělat. Přesunout doo presenteru
- Tharos
- Člen | 1030
Slug
je takový neologismus, kterým se programátoři CMS
systémů mstí koncovým uživatelům. :) Netuším, kde to vzniklo, delší
dobu je to přítomné minimálně ve WordPressu
(tam je i vysvětlení, co to je), ale nechápu, proč se ten nic
neříkající výraz tak uchytil. Taky jsme měli ve firmě v jednom systému
položku slug
a zkušenost byla, že 100% koncových uživatelů
netušilo, co to je.
- Droid
- Člen | 92
bojovyletoun napsal(a):
Je to určitě přínosný příklad.
Nápady, co bych vylepšil(vzhledem k minimalističnosti to jsou detaily):
- Přidal bych tam texylu a texy(jako service).
- Moc se mi nelíbí třída model, je to takový hegemon. Měl bych nápad, ale rozepíšu ho až jindy.
- zrušil bych Environment
- Selector už nemá find()
'slug' => $first_page->slug
podle mě nemá v bootstrapu a routeru co dělat. Přesunout doo presenteru
- Popřemýšlím, díky za tip :-)
- Klidně rozepiš, jsem pro. Je to z toho důvodu, aby to bylo co nejjednodušší. Pokud jde o nějaký model loader, tak ten by měla obsahovat další verze.
- Máš na mysli jen Environment::getService nebo i zbytek v bootstrapu?
- Dnes David psal, že ho zase bude mít
- Viz. https://forum.nette.org/…metr-v-route ale jinému řešení se taky nebráním.
- bojovyletoun
- Člen | 667
Rozepíšu jindy. Envoronment zrušit všude. Podle mě stačí do routeru
dát 'slug'=>null
(ještě zajistit aby se u první stránky
vypsal slug při tvorbě url ) v presenteru
function renderDefault($slug){
// neudržel jsem se a je tu i náznak modelu.
$s=$this->context->repository->articles; // volá $context->getservice('repository')->... nevím
//vrací něco jako BaseRepository('articles') případně Articles('articles') (existuje li třída Articles extends baseRepository)
$this->template->article= !$slug ? $s->findFirst() : $s->findBy('slug',$slug);
}
Editoval bojovyletoun (16. 6. 2011 13:48)
- Droid
- Člen | 92
bojovyletoun napsal(a):
Rozepíšu jindy. Envoronment zrušit všude. Podle mě stačí do routeru dát
'slug'=>null
(ještě zajistit aby se u první stránky vypsal slug při tvorbě url ) v presenterufunction renderDefault($slug){ // neudržel jsem se a je tu i náznak modelu. $s=$this->context->repository->articles; // volá $context->getservice('repository')->... nevím //vrací něco jako BaseRepository('articles') případně Articles('articles') (existuje li třída Articles extends baseRepository) $this->template->article= !$slug ? $s->findFirst() : $s->findBy('slug',$slug); }
No právě, jak tam dostat ten úvodní slug. Jinak díky, asi to implementuji, protože v bootstrapu se mi to taky nelíbí (současné řešení).
Jinak během dneška se na GitHubu objeví verze s primitivním ModelLoaderem a taktéž se pokusím zapracovat některé připomínky a později i jednoduchý kontaktní formulář na libovolné stránce.
- Filip Procházka
- Moderator | 4668
Pokud chceš tvořit něco ještě hodnotnějšího, přilep si do kuchařky další sekci „tvorba CMS“ nebo někam do Wiki si vytvoř sekci a piš tutoriál, jak jsi začal od začátku, co jsi kde a proč napsal a co jsi kde jak proč zrefaktoroval a přejmenoval. Myslím, že by to spoustě lidí pomohlo :)
- nanuqcz
- Člen | 822
Droid napsal(a):
No právě, jak tam dostat ten úvodní slug. Jinak díky, asi to implementuji, protože v bootstrapu se mi to taky nelíbí (současné řešení).
Podle mě to @bojovyletoun myslel nějak takhle:
bootstrap.php
$frontRouter[] = new Route('<slug [a-z0-9_-]+>', array(
'presenter' => 'Default',
'action' => 'page',
'slug' => NULL // slug prvního záznamu se načte až v presenteru
));
DefaultPresenter.php
public function actionPage($slug = NULL) {
if (is_null($slug)) $slug = $this->getService('model')->getFirstPage()->slug;
$this->page = $this->getService('model')->findBySlug($slug);
$this->menu = $this->getService('model')->getMenu();
if (!$this->page) {
throw new BadRequestException('Stránka nebyla nalezena!', 404);
}
}
public function renderPage($slug = NULL) {
if (is_null($slug)) $slug = $this->getService('model')->getFirstPage()->slug;
$this->template->page = $this->page;
$this->template->menu = $this->menu;
}
což je daleko čistší řešení, než jsem ti tehdy poradil já .-)
- Patrik Votoček
- Člen | 2221
Souhlasím s hosiplanem bylo by dobré k tomu sepsat u každého kroku co, proč a jak jsi dělal. Vzniknul by z toho pěkný tutoriál. :-)
- uestla
- Backer | 799
Zdravím a ptám se:
Je nějak (jakkoli) ošetřena duplicita slugu? A pokud ne, není to špatně? Tak trochu nevybíravě jsem se na to pokoušel upozornit přidáním stránky s takovým nadpisem, jehož převod vede na stejný slug jako u jiné stránky s odlišným nadpisem.
Čili jak je na tom ošetření duplicity? Ať už na straně databáze (UNIQUE), tak na straně aplikace (při přidávání do databáze kontrolovat kód vyhozené výjimky způsobené právě UNIQUE indexem a uživateli zobrazit lidskou chybovou zprávu).
Nette\Utils\Strings::webalize('Hómě'); // = home
Nette\Utils\Strings::webalize('Home'); // = home
- Filip Procházka
- Moderator | 4668
Děkuješ za něco, co se ti ani nepovedlo zprovoznit a pravděpodobně ani netušíš jak to funguje :) A aby toho nebylo málo, tak pošleš naprosto irelevantní řádek chyby. Přičti si dva bludišťáky :)
- Droid
- Člen | 92
Omlouvám se, byl jsem teď trošku mimo (osobní problémy). Už se to trošku uklidnilo, tak jsem aspoň hodil na nový hosting aplikaci a pushnul změny, co mi už skoro měsíc leží na disku. Jsou fixnuté některé chybičky a je tam použit ten nejprimitivnější ModelLoader. Pokud tam chcete zapracovat řešení z kuchařky, je to na Vás.
- Droid
- Člen | 92
uestla napsal(a):
Zdravím a ptám se:
Je nějak (jakkoli) ošetřena duplicita slugu? A pokud ne, není to špatně? Tak trochu nevybíravě jsem se na to pokoušel upozornit přidáním stránky s takovým nadpisem, jehož převod vede na stejný slug jako u jiné stránky s odlišným nadpisem.
Čili jak je na tom ošetření duplicity? Ať už na straně databáze (UNIQUE), tak na straně aplikace (při přidávání do databáze kontrolovat kód vyhozené výjimky způsobené právě UNIQUE indexem a uživateli zobrazit lidskou chybovou zprávu).
Nette\Utils\Strings::webalize('Hómě'); // = home Nette\Utils\Strings::webalize('Home'); // = home
Opraveno.
Editoval Droid (27. 7. 2011 23:12)
- joe
- Člen | 313
Tak jsem se na to podíval a začátečníkům se to bude hodit, dobrá práce.
Tak, jako k většině věcem, i tady mám několik připomínek, možná se to protáhne :-)
- tím, že jsi opravil „slug“, jsi znemožnil ukládání již existujících záznamů (editaci) – píše „Nemůžete přidat existující stránku.“
- nevím kde jsi viděl používání funkce
is_null
, používej místo toho klasické porovnání$a === NULL
(je i rychlejší :-) - v modelech by se hodil taky nějaký ten
BaseModel
, kde by byl přístup k databázi - to co máš v
DashboardPresenter
u v AdminModulu ve startup metodě, to by se hodilo dát doBasePresenter
u. Takhle vytvoříš další presenter a máš zaděláno na malér, že se tam někdo po uhodnutí adresy dostane. - u
BadRequestException
je výchozí kód 404, nemusíš ho uvádět (FrontModel\DefaultPresenter
a možná i jinde)
PS: slovo slug jsem nikdy v životě neviděl ani neslyšel, pro tohle k čemu to je použité mám nějak zažité „ident“ :-)
Editoval joe (4. 8. 2011 0:57)
- Patrik Votoček
- Člen | 2221
joe napsal(a):
PS: slovo slug jsem nikdy v životě neviděl ani neslyšel, pro tohle k čemu to je použité mám nějak zažité „ident“ :-)
- joe
- Člen | 313
@22 – ident jako zkratka pro identifikátor :) slug mi na první pohled nic neřekne
@xxxObiWan – myslel jsem to tak, že tu část kódu co se tam opakuje, bych hodil do předka, ne? Konkrétně tuhle
/** @var Nette\Database\Connection */
public $database;
public function __construct($connection) {
$this->database = $connection;
}
Editoval joe (4. 8. 2011 20:13)
- nanuqcz
- Člen | 822
Podle mě by bylo nejlepší udělat multijazyčnou verzi v nějaké větvi, nebo nějak odděleně. Prostě aby bylo to klasické krásně jednoduché NanoCMS :-), a kdo by chtěl, aby se mohl podívat, co je potřeba doplnit, aby vzniklo multijazyčné NanoCMS.
Pokud by se ti teda chtělo, nevím kolik by to bylo práce navíc. GIT prý sice nějak podporuje práci na více větvích jednoho projektu, ale do GITu zas tak nevidím, takže nevím, kolik času by to skutečně ušetřilo…
- pavel.stumpf
- Člen | 6
Ahoj,
jen drobná chybka, které jsem si všiml, když jsem to testoval:
V administraci, při úpravě některé položky, když změním jen obsah pole
Text a zkusím uložit, tak se to neprovede s hláškou „Nemůžete přidat
existující stránku.“
Editoval pavel.stumpf (14. 9. 2011 12:44)
- Zdeno1981
- Člen | 115
Ahoj,
chtěl bych se zeptat zda by někdo neporadil jakým způsobem udělat další
presenter v frontModule, např. KontaktPresenter kvůli odesilacího
formuláře, ale netuším jak by se to dalo vyřešit v routeru.
// Setup router
$application->onStartup[] = function() use ($application, $context) {
$router = $application->getRouter();
// mod_rewrite
$router[] = new Route('index.php', 'Front:Default:page', Route::ONE_WAY);
$router[] = $adminRouter = new RouteList('Admin');
$adminRouter[] = new Route('admin/<presenter>/<action>[/<id>]', 'Dashboard:default');
$router[] = $frontRouter = new RouteList('Front');
$frontRouter[] = new Route('<slug [a-z0-9_-]+>', array(
'presenter' => 'Default',
'action' => 'page',
'slug' => NULL,
));
// $router[] = new SimpleRouter('Front:Default:default');
};
Editoval Zdeno1981 (24. 1. 2012 17:48)
- Droid
- Člen | 92
Zdeno1981 napsal(a):
Ahoj,
chtěl bych se zeptat zda by někdo neporadil jakým způsobem udělat další presenter v frontModule, např. KontaktPresenter kvůli odesilacího formuláře, ale netuším jak by se to dalo vyřešit v routeru.
Ahoj, zrovna jsem se vrátil po dost dlouhé době k Nette a zrovna NanoCMS
předělávám. Momentálně dělám galerii, ale formulář není problém.
Mám to vyřešené asi takhle:
V datab. tabulce ‚pages‘ mám sloupec ‚contact_form‘, který má buď
0 nebo 1. Do presenteru, který se stará o stránky ve FrontModule jsem
přidal definici formuláře + callback. V šabloně stránek pak mám
něco jako:
{block #content}
<h2 n:block="title">{$page->title}</h2>
<p>{!$page->text}</p>
{if $page->contact_form}
{control contactForm}
{/if}
{/block}
A v administraci mám potom u detailu každé stránky checkbox, jestli chci na té stránce zobrazit ten kontaktní formulář nebo ne. Nahodím ukázku do dema a až dodělám i galerii, hodím to na github. Mělo by to být hotové během 2 dnů, sám to teď potřebuju na jeden projekt.
- ViPEr*CZ*
- Člen | 817
Droid napsal(a):
Jestli někdo čeká na verzi s galerií, tak bude o víkendu. Poslední 2 dny jsem se pral s vlastní komponentou pro multiupload, protože žádnou z doplňků se mi nepodařilo rozchodit a hlavně si s sebou táhly hodně závislostí.
Na multiupload bude dobrej ajax2, ale ještě musíme chvíli počkat na podporu ze strany všech prohlížečů.
- iguana007
- Člen | 970
Mirek_R napsal(a):
Čau hoši kde stáhnu nejnovější verzi ? Nějaký návod jak to rozchodit ? zkoušel jsem to na local hostu ale háže to Error díky …
Je to nová verze Nette ?
Mirek
Error říkáš? OK, moment, pohledám křišťálovou kouli, tam by se mi měl ten error vypsat a pak ti můžeme poradit.
- krato
- Člen | 1
Mirek_R napsal(a):
could not find driver problém v localhostu už jsem nainstaloval jinej :) díky
Databáze demo.db je ve formátu sqlite2, pro který již WAMP 2.2, resp. PHP
distribuce v něm (PHP 5.4.3), nemá driver, protože má driver snad jen pro
sqlite3. Pomůže např.:
http://blog.johnjosephbachir.org/…-3-database/
Zasekl jsem se na tom na 2 dny! Též mě to málem odradilo od celého Nette. Buď jsem velmi velmi nepozorný a za to se omlouvám a někde jsem něco přehlédl nebo by to chtělo tento problém vyřešit tak, aby se na tom již nikdo nezasekával, např. pro demo účely dát do toho adresáře obě verze nebo tak něco.
- Jakub Kontra
- Člen | 30
Pěkný příklad!.. :)
Škoda že není ke stažení nejnovější verze i s galerií, rád bych se mrkl jak je řešená
jinak
++! :)