Ukázková microsite (včetně mini-backendu)

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

Ahoj,

minulý týden jsem vyráběl pro jednoho svého klient malou microsite a napadlo mě, že bych výsledek mohl přetavit i v jednoduchou ukázku pro ty, kteří začínají s Nette.

Zde je výsledek mého snažení.

Zadání bylo úplně jednoduché. Klient potřeboval dvoujazyčnou microsite (ve skutečnosti běží každá jazyková verze na své vlastní doméně 2. řádu, ale v ukázce jsem router zjednodušil na /cz a /en). Říkal, že si sám nepotřebuje upravovat celkovou informační architekturu, ale rád by měl možnost sám si spravovat hlavní obsahy stránek, aby mě neotravoval s každou prokotinou (změnou ceny, jazykovou korekturou…).

Návod na zprovoznění je v readme.


Snažil jsem se, aby byly v aplikaci použity různé best practices (nebo alespoň postupy, které já osobně za best practices považuji a dlouhodobě se mi osvědčily). Vítám oponenturu, pokud by vám některý z prezentovaných postupů přišel kontraproduktivní nebo špatný!

Musím jen upozornit na jednu věc, která je v aplikaci odfláknutá: dostupné jazyky jsou hard-coded v kódu a redundandně i v databázi. Plánuji, že tuhle ne úplně hezkou věc někdy ve volné chvíli odstraním…

Ať vám ukázka slouží!

mrfrostikcz
Člen | 17
+
0
-

Super, určitě se bude hodit. Palec jde nahoru.

David Ďurika
Člen | 328
+
0
-

preco pises rucne Factory napr tu namiesto implement: ?

Jan Suchánek
Člen | 404
+
+1
-

Je to fajn, jen mě rozhodila ta adresářová struktura.

Tharos
Člen | 1030
+
0
-

@achtan: Je to proto, protože vygenerovaná factory by té vytvářené instanci nepředala ten parametr $contents. AFAIK podobné věci zatím generované factory neumí. Nebo se mýlím?

Pokud bych tam tenhle parametr za běhu předat nepotřeboval, rozhodně bych volil generovanou factory.

David Matějka
Moderator | 6445
+
+2
-

@Tharos:

interface ContentsFormFactory
{
	/**
	* @return ContentsForm
	*/
	public function create(array $contents);
}
-
	implement: ContentsFormsFactory
	parameters: [array contents] #nebo nejak tak
	arguments: [..., %contents%]

(u starsich verzi se musi uvest i class kvuli bugu)

pripadne v compiler extension:

$builder->addDefinition('foo')
	->setImplement('ContentsFormsFactory')
	->setArguments([1 => new PhpLiteral('$contents')]); //snad to pude takhle jako druhy parametr :)

v compiler extensio neni nutno uvadet parameters, ty se autodetekujou

Editoval matej21 (24. 6. 2014 16:33)

Tharos
Člen | 1030
+
+3
-

@jenicek: To chápu. :) Je trochu více feature based než type based. Jde o rozdíl typu:

Model
- Entity
   - Author
   - Book
- Repository
   - AuthorRepository
   - BookRepository

versus

Author
- Model
  - Author
  - AuthorRepository
Book
- Model
  - Book
  - BookRepository

Mám dlouhodobější zkušenost, že feature based rozdělení (to je to druhé) je u rozsáhlejších aplikací mnohonásobně přehlednější a lépe znovupoužitelné, a proto už jej osobně používám všude. I na menších záležitostech.

Tharos
Člen | 1030
+
0
-

@matej21: No super, díky! :) Vyzkouším a rád to v kódu vylepším.

Michal Vyšinský
Člen | 608
+
+1
-

matej21 napsal(a):

Doporučil bych neautowirované parametry dávat jako poslední, takže:

  • v ContentForm mít jako první parametry ty neautowirované (zde array $contents)
  • factory je ok
  • v neonu pak odpadá nutnost psát ty tečky takže: arguments: [%contents%]
  • v extension IMO lze předat ['contents' => new PhpLiteral('$contents')]

A ještě jedna lahůdka z nejnovějšího Nette:

- implement: ContentsFormsFactory
  parameters: [array contents]
  arguments: [..., %contents%]

Editoval Michal Vyšinský (24. 6. 2014 16:50)

David Matějka
Moderator | 6445
+
+1
-

@MichalVyšinský
j, ja to tak bezne delam, jen jsem ukazoval kompatibilni kod s tim Tharosovym

Jan Suchánek
Člen | 404
+
0
-

@Tharos: je mi to jasné, jen než se člověk zorientuje, tak je trochu paf :) Nevyplatilo by se rovnou používat Flame\Modules?

Editoval jenicek (24. 6. 2014 19:40)

Tharos
Člen | 1030
+
0
-

@MichalVyšinský @matej21 @achtan

Ta kouzla s parametry u továrniček opravdu funugjí, fakt díky za dovzdělání. Já jsem věděl, proč tu microsite zveřejnit ;).

Tím jsem se zbavil ručně nadefinované ContentFormFactory a dokonce i NavigationFactory.

Ty generované factories jsou skvělá věc, neskutečně šetří psaní.

Editoval Tharos (24. 6. 2014 23:32)

David Ďurika
Člen | 328
+
0
-

Tharos napsal(a):

@jenicek: To chápu. :) Je trochu více feature based než type based. Jde o rozdíl typu:

tiez som sa feature based dokonca som to na niektorych projektoch implementoval aj v ramci samotnej Application (presenter, comntrol, template) tu je o tom diskusia

kcermak
Člen | 3
+
-1
-

Aniž bych to nějak zkoumal: po čerstvé instalaci a projití všech kroků z readme při prvním spuštění:

Parse Error: syntax error, unexpected '['

File: ...\app\Microsite\LeanMapper\DI\LeanMapperExtension.php:33
33:                ->setClass('LeanMapper\Connection', [$config]);

PHP 5.3.28
Apache/2.2.25 (Win32) PHP/5.3.28
Tracy 2.2.1
Michal Vyšinský
Člen | 608
+
+2
-

@kcermak jelikož máš PHP 5.3, tak [$config] musí být array($config). Zkrácený zápis array je v PHP až od 5.4

David Ďurika
Člen | 328
+
+2
-

mam taky pocit ze to nepobezi ani na 5.4 ale az na 5.5+ lebo ->from(Page::class, 'p')

Editoval achtan (26. 6. 2014 14:57)

Michal Vyšinský
Člen | 608
+
+1
-

aha, toho jsem si nevšiml, zdrojáky jsem neprojížděl :)

Možná by nebylo špatné napsat požadavky do readme

Editoval Michal Vyšinský (26. 6. 2014 15:21)

Tharos
Člen | 1030
+
0
-

Ty jo, ::class je v PHP koukám až od 5.5. Taková skvělá věc… No nic, PHP 5.4 by to asi podporovat mělo, co? Asi tyhle části přepíšu… A do readme doplním jako minimální verzi PHP 5.4.

Ale až k PHP 5.3 bych se snížil nerad…

Editoval Tharos (26. 6. 2014 16:33)

Michal Vyšinský
Člen | 608
+
+2
-

@Tharos já ve svém kódu přidávám třídám konstanty classname = __CLASS__. A používám místo ::class ono ::classname. Až budu chtít přestat podporovat 5.4, tak jednoduchý Find&Replace to jistí :)

Tharos
Člen | 1030
+
+1
-

@MichalVyšinský To je moc hezký work around :).

V ukázce pro začátečníky by ale možná zbytečně mátl. Napadlo mě udělat to takhle:

->from('Microsite\Domain\Page', 'p') // you can use Page::class instead of string in PHP 5.5

Editoval Tharos (26. 6. 2014 16:44)

Jan Endel
Člen | 1016
+
0
-

Můžeš to řešit podobně jako to bylo/je v Nette a to:

->from('Microsite\Domain\Page'/**PHP 5.5: Page:class*/, 'p')
Jan Tvrdík
Nette guru | 2595
+
+4
-

@JanEndel: To je dobrý tak na strojový zpracování, pro neznalého je to hůře čitelné, než to, co navrhuje @Tharos výše.

David Ďurika
Člen | 328
+
0
-

@JanTvrdík podla mna je @JanEndel riesenie uplne v pohode… nieje to az tak zahadne napisane aby to co i len zaciatocnik nepochopil

kcermak
Člen | 3
+
0
-

David Ďurika napsal(a):
mam taky pocit ze to nepobezi ani na 5.4 ale az na 5.5+ lebo ->from(Page::class, 'p')

Skutečně na PHP 5.4.30 dává:

Parse Error: syntax error, unexpected 'class' (T_CLASS), expecting identifier (T_STRING) or variable (T_VARIABLE) or '{' or '$'

<?php
File: ...\app\Microsite\Application\AdminPresenter.php:51
51:                ->from(Page::class, 'p')

PHP 5.4.30
Apache/2.2.25 (Win32) PHP/5.4.30
Tracy 2.2.1
?>

Opravy:

<?php
...\app\Microsite\Application\AdminPresenter.php
51, 81 ->from('Microsite\Domain\Page', 'p') // you can use Page::class instead of string in PHP 5.5

...\app\Microsite\Auth\Authenticator.php
40: ->from('Microsite\Auth\User', 'u') // you can use User::class instead of string in PHP 5.5

...\app\Microsite\Routing\DatabaseRouter.php
46, 94 ->from('Microsite\Domain\Page', 'p') // you can use Page::class instead of string in PHP 5.5

...\app\Microsite\Navigation\Navigation.php
148 ->from('Microsite\Domain\Page', 'p') // you can use Page::class instead of string in PHP 5.5
?>

Potom už funguje.

Editoval kcermak (4. 7. 2014 13:47)

Tharos
Člen | 1030
+
+4
-

Ahoj,

dneska přibylo v Microsite pár novinek.

1. Opravil jsem kompatibilitu s PHP 5.4 a do readme jsem doplnil sekci Requirement.

2. Jazykové verze už nejsou hard coded, jak jsem zmiňoval ve svém prvním postu.

Myslím, že stojí za povšimnutí, jak je nyní práce s jazykem vyřešená. Využívám toho, že persistentní parametr v presenteru nemusí být pouze skalárního typu (což se asi příliš neví a ani nepoužívá), takže já udržuji přímo instanci Lang. Hodně se mi na tom líbí to, že je vše konzistentní – není to tak, že by se někde pracovalo s instancí Lang a jinde s ID (rozuměj kódem) jazyka, což je takové výchozí řešení. Všude se pracuje s instancí Lang.

Aby to celé fungovalo, je zapotřebí tomu přizpůsobit routování (zde, zde a zde).

Třešničkou na dortu je Lang::__toString, takže například v šablonách, do kterých si předáte aktuální jazyk, můžete rovnou psát {$lang} namísto {$lang->id}. V ukázce je to vidět v připojování stylů.

3. Doplnil jsem v rámci Microsite\LeanMapper jednoduchý package systém, který usnadňuje správu entit z různých jmenných prostorů. Nově už není zapotřebí žádné ošklivé if ... elseif ... elseif ... else konstruce v Mapper::getEntityClass, ale packages se spravují přes jednoduchý json.

4. Vylepšil jsem rozdělení jmenných prostorů. Nově vznikl prostor Microsite\Localisation, který obsahuje entitu Lang a fasádu Langs a původní Domain jsem přejmenoval na výstižnější (doufám) Site.

5. Upravil jsem konfiguraci tak, že připojení k databázi se nekonfiguruje přes obecné parametry, ale přímo v sekci patřící Lean Mapper extenzi. Je to jenom takové kosmetické jednodušení…


Aktuálně v Microsite nenacházím žádný technologický dluh a dost si za jejím kódem stojím, a proto jsem dnešní verzi otagoval jako v1.

Kdybyste měli kdokoliv námět na nějaké další rozšíření, sem s tím. Rád se o tom pobavím a eventuálně ukázku rozšířím.

Editoval Tharos (9. 7. 2014 9:45)

Jan Suchánek
Člen | 404
+
0
-

@Tharos Koukám, že routě předáváš celý objekt to je fajn, já myslel, že tam patřej jen parametry, tzn. klíďo objekt Page by mohl klidně rozhodovat jaký presenter se pustí, což ty už tam máš, ale možná by tam mohlo být i verzování.

Jan Suchánek
Člen | 404
+
0
-

@tharos Mohu ti poslat pull s default lang? Ještě mě napadlo kdyby se používalo standardní route možná by to s tím lang bylo jednodušší, nebo je důležité mít lang jako Lean Mapper Entitu?

kcermak
Člen | 3
+
0
-

Jak prosimvás psát odkazy?

Když chci z default stránky udělat odkaz na twoColumns, tak napíšu do default.latte

<a href="{plink Page: page => 'twoColumns'}">See our contacts!</a>

Ale vyhodí to

Trying to get property of non-object
File: ...\app\Microsite\Routing\DatabaseRouter.php:112
112:            $relativeUrl = $lang . ($page->homepage ? '' : '/' . $page->webalizedName);

Vidím, že PagePresenter má parametr $currentPage, ale nevím jak ho mám ze šablony nastavit.

Jan Suchánek
Člen | 404
+
0
-

@kcermak jednak je lepší používat <a n:href=" … a jinak curentPage je pravě předaná zde.

Je potřeba pochopit že Tharos v Microsite používá DatabaseRouter který překládá url na LM Entitu Page, jinej router tam nemá, a ani neni potřeba. Překlad z id na url tam není, ale asi to nebylo ani požadované.

Tharos
Člen | 1030
+
0
-

@kcermak: Odkazovat z jedné stránky na jiné lze úplně jednoduše:

{plink Page: pageId => 2}

Pokud nepřecházíš v odkazu na jinou jazykovou verzi, úplně to stačí, protože druhý potřebný parametr, lang, se předá automaticky (je persistentní).

Pokud přecházíš v odkazu na stránkou z jiné jazykové verze, odkaz lze vytvořit následovně:

{link Page: pageId => 7, lang => en}
Tharos
Člen | 1030
+
0
-

@jenicek: K Tvým dotazům:

objekt Page by mohl klidně rozhodovat jaký presenter se pustí, což ty už tam máš, ale možná by tam mohlo být i verzování.

Co si mám představit pod tím verzováním? :) Jinak volbou, jaký presenter spustit, bych entitu Page osobně určitě „nezatěžoval“. Tohle je další zodpovědnost, která nejlépe sluší routeru.

Mohu ti poslat pull s default lang? Ještě mě napadlo kdyby se používalo standardní route možná by to s tím lang bylo jednodušší, nebo je důležité mít lang jako Lean Mapper Entitu?

Pro jednoduchost bych v té ukázce výchozí jazyk radši nijak neřešil. Jedna standardní Route se používá, ale i ta má nastavený filtr, aby jazyk převedla na entitu. Není nezbytně nutné mít lang v parametrech presenterů jako entitu, ale mně to přijde docela elegantní.

V modelu pak mít jazyk reprezentovaný jako enitu osobně považuji za zdaleka nejvýhodnější.

Jan Suchánek
Člen | 404
+
0
-

Tharos napsal(a):

Co si mám představit pod tím verzováním? :) Jinak volbou, jaký presenter spustit, bych entitu Page osobně určitě „nezatěžoval“. Tohle je další zodpovědnost, která nejlépe sluší routeru.

Ok, Page by obsahovala jakyho je presenteru a rozhodoval by samozřejmě router, jaky presenter nakonec pustí.
Verzování bylo myšleno podobné ukládání obsahu jako má třebas Wordpress (samozřejmě tohle se do Microsite nehodí).

Pro jednoduchost bych v té ukázce výchozí jazyk radši nijak neřešil. Jedna standardní Route se používá, ale i ta má nastavený filtr, aby jazyk převedla na entitu. Není nezbytně nutné mít lang v parametrech presenterů jako entitu, ale mně to přijde docela elegantní.

V modelu pak mít jazyk reprezentovaný jako enitu osobně považuji za zdaleka nejvýhodnější.

Ok mě se nelíbí, že po po zprovoznění Microsite se musí vybrat jazyk a výchozí stránka je 404.

petvo
Člen | 2
+
0
-

Ahoj. V Nette jsem začátečník. Prošel jsem první částí „Začínáme“. První aplikaci podle QuickStartu jsem zprovoznil a i trochu rozšířil, takže přirozeně další cesta vedla do tohoto příspěvku. Stáhnul jsem si aplikaci „Microsite-v1“ s tím, že kódy zkopíruji do složky „sandbox“, provedu nějakou parametrizaci a aplikace poběží. Po stažení aplikace a rozbalení jsem zjistil, že složky jsou zde přeházené (struktura neodpovídá popisu v Začínáme) a aplikaci se mi nedaří zprovoznit. Prosím, můžete mi někdo poradit a aplikaci zprovoznit? Děkuji.

Editoval petvo (14. 10. 2014 19:36)

Šaman
Člen | 2666
+
0
-

Nette jako framework adresářovou strukturu moc nevyžaduje, jen relativní umístění šablon vůči presenterům (a to se dá snadno upravit). Vše ostatní je jen na tobě, nicméně Sandbox je pro většinu běžných aplikací dobrý začátek, kde už je všechno nějak ukázkově vyřešené. Ale mě třeba adresářová struktura Sandboxu nevyhovuje, mám rád šablony ve stejném adresáři u komponenty, i presenteru.

A k věci:
Na Tharosovu Microsite budeš potřebovat jen composer a ten už si závislosti natáhne. Případně do /vendor/others nahrát všechno ručně.

Editoval Šaman (14. 10. 2014 19:39)

petvo
Člen | 2
+
0
-

Díky za reakci. Možná tato informace měla být uvedena hned na začátku příspěvku. Tato aplikace asi zatím ještě není pro mě.

Hledám nějakou jednoduchou ukázkovou aplikaci, která by tak trochu navazovala na aplikaci v QuickStartu, kterou se mi podařilo rozšířit o stránkování, přidávání nových článků (včetně editace) + komentářů (práce s formulářem), přihlášení uživatelů (+ rozdělení uživatelů do rolí – využívám pro zobrazení linků podle role přihlášeného uživatele).

Čili hledám nějakou „Microsite“, která navazuje na QuickStart a přesahuje mé rozšíření. Je zde něco takového? Děkuji.

Editoval petvo (14. 10. 2014 20:11)

Azathoth
Člen | 495
+
0
-

@petvo
https://github.com/nette/examples
tohle by tě mohlo zaujmout…

Editoval Azathoth (14. 10. 2014 21:01)

Šaman
Člen | 2666
+
0
-

Můžeš se podívat na můj Todolist, je v něm použitý LeanMapper a proti Sandboxu nemá moc změn. Jen šablony jsou vždy u „svého“ php souboru, je přidaná zkratka pro barDump() a asi pár dalších maličkostí. Vycházím totiž ze svého Skeletonu (změny proti Sandboxu jsou tam popsané; authorizator už tam je, teď jsem zjistil, že jsem neaktualizoval readme)

Ja
Člen | 260
+
0
-

Dotaz prosim, k cemu je v aplikaci tolik interfacu, ktere treba ani nejsou nikde implementovany?
INavigationFactory
ContentRepository

nebo trida Content, ktera je uplne prazdna?

diky moc

David Matějka
Moderator | 6445
+
0
-

@Ja

Dotaz prosim, k cemu je v aplikaci tolik interfacu, ktere treba ani nejsou nikde implementovany?

https://doc.nette.org/…dependencies#…

nebo trida Content, ktera je uplne prazdna?

v leanmapperu se entita konfiguruje anotacema nad tridou, viz http://www.leanmapper.com/…t/kapitola-3

ic
Člen | 430
+
0
-

nemusí microsite být na Microframework-u? :)

Felix
Nette Core | 1247
+
+1
-

ic napsal(a):

nemusí microsite být na Microframework-u? :)

Na necem podobnem jsem zacal nedavno pracovat Minetro/Micro

witas
Člen | 1
+
0
-

Dobrý den,
jsem úplný zelenáč a při postupování podle readme jsem se dostal jen na nastylovanou page 404. Mohl byste mi prosím poradit?

ic
Člen | 430
+
0
-

Felix napsal(a):

Na necem podobnem jsem zacal nedavno pracovat Minetro/Micro

pěkná věcička, sice trošku složitá :D

Felix
Nette Core | 1247
+
0
-

ic napsal(a):

pěkná věcička, sice trošku složitá :D

Zatim to moc v MicroPresenteru nejde jednoduseji, pokud to ma byt trochu dynamicke :-) Nebo jsem na to neprisel. Beru to spis jako ukazku co vsechno jde a jak pracovat s vice balickama dohromady (neco jako nette micro).