Ukázková microsite (včetně mini-backendu)
- Tharos
- Člen | 1030
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.
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ží!
- Tharos
- Člen | 1030
@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
@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
@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.
- Michal Vyšinský
- Člen | 608
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
@MichalVyšinský
j, ja to tak bezne delam, jen jsem ukazoval kompatibilni kod s tim
Tharosovym
- Jan Suchánek
- Člen | 404
@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
@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
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
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
@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
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
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)
- Michal Vyšinský
- Člen | 608
@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í :)
- Jan Tvrdík
- Nette guru | 2595
@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
@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
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
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
@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
@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
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
@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
@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
@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
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
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
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
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
@petvo
https://github.com/nette/examples
tohle by tě mohlo zaujmout…
Editoval Azathoth (14. 10. 2014 21:01)
- Šaman
- Člen | 2666
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)
- David Matějka
- Moderator | 6445
@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
- Felix
- Nette Core | 1247
ic napsal(a):
nemusí microsite být na Microframework-u? :)
Na necem podobnem jsem zacal nedavno pracovat Minetro/Micro
- ic
- Člen | 430
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
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).