NanoCMS – Nette example dynamického webu

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Droid
Člen | 92
+
0
-

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 :-)

Screenshot webu

Screenshot adminu

Editoval Droid (29. 8. 2012 13:15)

Filip Procházka
Moderator | 4668
+
0
-

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.

Droid
Člen | 92
+
0
-

HosipLan: No ten post jsem objevil až u implementace menu, tak spíš s tím menu jsem se nejvíc inspiroval :-) Mockrát ti děkuji. Třídu model jsem tak nechal z CD-collection, ale díky za tip, přejmenuji ji nějak rozumně.

Patrik Votoček
Člen | 2221
+
0
-

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
+
0
-

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
22
Člen | 1478
+
0
-

se zeptám jako uplnej idiot, co je to slug? s tím se nějak někde počítá? Proč slug

Tharos
Člen | 1030
+
0
-

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.

grey
Člen | 94
+
0
-

22 wrote:

se zeptám jako uplnej idiot, co je to slug? s tím se nějak někde počítá? Proč slug

Je to třeba titulek článku přepracovaný na formu která se dá použít v url. Dá se na to použít třeba funkce Nette\Utils\Strings::webalize ;)

22
Člen | 1478
+
0
-

v tom případě jsem za odstranění tohoto a nahrazením minimálně něčím, co bude Nette-slug a dohledatelné v dokumentaci :-) to byl ftip…

Droid
Člen | 92
+
0
-

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
+
0
-

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
+
0
-

Doplněn link na GitHub

Droid
Člen | 92
+
0
-

Díky za odstranění Environment, zrovna jsem to chtěl dělat commit a pushnout zmeny :-) Jinak Environment tam bylo proto, že jsem vycházel z aktuálních Nette examples. Možná by to chtělo upravit.

Editoval Droid (16. 6. 2011 19:00)

Vojtěch Dobeš
Gold Partner | 1316
+
0
-

Rádo se stalo :). Examples už jsou taky upravené.

Droid
Člen | 92
+
0
-

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 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);
}

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
+
0
-

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
+
0
-

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
+
0
-

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. :-)

one-two
Člen | 80
+
0
-

Hezký, zrovna sem dělal jeden web kde sem potřeboval přesně takhle proměnné menu s jen jednim presenterem, díky :)

uestla
Backer | 799
+
0
-

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
Semik
Backer | 135
+
0
-

Stejně tak slug s názvem ‚admin‘.

uestla
Backer | 799
+
0
-

Tys mu to rozbil! :-)

Droid
Člen | 92
+
0
-

Pardón, nestihl jsem to zveřejnit před dovolenou. Každopádně dnes návrat, po vydatném spánku čekejte vylepšenou verzi (+pár fixů).

lolek57
Člen | 1
+
0
-

Ahoj, diky za tento example, jsem za nej vdecny. Mam jen maly problem se spustenim. Nevím proč mi to haze chybovou hlasku:
19: $class = ‚Nette\\Database\\Connection‘; $service = new $class($container->expand(‚sqlite2:%appDir%/models/demo.db‘));

Filip Procházka
Moderator | 4668
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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 DashboardPresenteru v AdminModulu ve startup metodě, to by se hodilo dát do BasePresenteru. 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
+
0
-

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“ :-)

http://codex.wordpress.org/Glossary#Slug

uestla
Backer | 799
+
0
-

Ohledně unikátnosti slugu je lepší přímo při surovém vkládání do databáze zachytávat – v tomhle případě – PDOException a podle kódu výjimky nabídnout uživateli relevantní chybovou hlášku. Vyřeší se tím jak atomicita, tak úprava záznamu.

joe
Člen | 313
+
0
-

Patrik Votoček – napsal jsi zrovna na tu nejnepodstatnější část, kterou jsem přidal až po zeditování a i když už tady na to odpověď dávno byla, přesto díky.
Jinými slovy jsem chtěl napsat, že použival jsem ident, používám ident a budu používat ident :-)

22
Člen | 1478
+
0
-

…slovo ident jsem nikdy v životě neviděl ani neslyšel, pro tohle k čemu to je použité mám nějak zažité slug :-)

nanuqcz
Člen | 822
+
0
-

v modelech by se hodil taky nějaký ten BaseModel, kde by byl přístup k databázi

Ahoj, jak to myslíš? Databáze se předává každému modelu automaticky díky DI configuratoru, ne?

joe
Člen | 313
+
0
-

@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)

tomasnikl
Člen | 137
+
0
-

Tak to je super, s Nette teprve zacinam a presne takovyto jednoduchy priklad se hodi. Celkem by me jeste zajimalo, jak se resi v praxi vicejazycnost… bylo by dobre do cms zahrnout alespon 2 jazyky, jako priklad pro novacky to urcite bude velmi uzitecne.

Jeste jednou diky

Droid
Člen | 92
+
0
-

No teď je tam pár bot, většinu mám fixlou, tak to hodím na Github ASAP. Na vícejazyčnosti popřemýšlím, díky za inspiraci.

nanuqcz
Člen | 822
+
0
-

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…

mrataja
Člen | 57
+
0
-

Nepřidal by jsi prosím i možnost víceúrovňové navigace? Na fóru je na toto téma plno postů, ale dokud to neuvidím pohromadě, tak to snad nikdy nezvládnu. Díky

pavel.stumpf
Člen | 6
+
0
-

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
+
0
-

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
+
0
-

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.

Droid
Člen | 92
+
0
-

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í.

Mirek_R
Člen | 22
+
0
-

Č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

ViPEr*CZ*
Člen | 817
+
0
-

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
+
0
-

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.

Mirek_R
Člen | 22
+
0
-

could not find driver problém v localhostu už jsem nainstaloval jinej :) díky

Editoval Mirek_R (7. 4. 2012 17:41)

krato
Člen | 1
+
0
-

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.

Droid
Člen | 92
+
0
-

No, problém bude totiž v tom, že do examples se občas dostane bordel :-) Nano vychází z CD-Collection příkladu a tam v době psaní byl formát jen pro sqlite2.
Až se zorientuju v těch změnách ohledně DI, načítání modelů a komponent, bude restart projektu.

Jakub Kontra
Člen | 30
+
0
-

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

++! :)

Jirda
Člen | 103
+
0
-

Pěkná práce. Jednoduché, přímočaré. +1