Poznámky k návrhu CMS Kdyby

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Filip Procházka
Moderator | 4668
+
0
-

CMS Kdyby

Zdravím,
tohle je návrh (moje poznámky) na CMS Kdyby. Chci vědět co si o tom myslí ostatní :)
Někoho možná napadne, že to trochu připomíná Nellu, ale na svoji obranu prohlašuji, že Nella mi jenom zamotala hlavu a vůbec jsem ji nepochopil :P

github: https://github.com/Kdyby
vyvíjet budu veřejně, licence bude nějaká open-source ve stylu „dělej si s tím co chceš“ takže můžete vesele kuchat :)

Použít:

  • Nette
  • dibi
  • notORM (od Jakuba Vrány) (né nezbytně)
  • jQuery (možná UI)

Adresářová struktura

  • app
    • templates (chmod 777)
      • layouts
        • web.simple.phtml
        • web.rightmenu.phtml
        • eshop.common.phtml
        • league.common.phtml
        • league.no-rightpanel.phtml
      • mails
    • addons (chmod 777)
      • ContactForm
        • templates
        • ContactForm.php
        • loader.php
      • Paginator
        • templates
        • Paginator.php
        • loader.php
      • PhaseForm
        • templates
        • PhaseForm.php
        • loader.php
    • modifications (chmod 777)
    • temp (chmod 777)
    • log (chmod 777)
    • bootstrap.php
  • libs
    • Kdyby
    • Nette
    • notORM
    • dibi
  • document_root
    • index.php

bootstrap.php

  • ponechat načítání tříd
  • nastavení přesunout do třídy „Kdyby“
// ...
require LIBS_DIR . '/Nette/loader.php';
require_once LIBS_DIR . '/dibi/dibi.php';

// ...
Environment::loadConfig();

$application = Environment::getApplication();

$application->configure();
$application->run();
class Kdyby extends Application {}

Přepsání v configu třídy Application za vlastní s metodou configure, která navěsí na Application->onStartup metody, spojením s databází počínaje až po konfiguraci routeru.

Routování

Router bude potřeba přepsat na seo-like spolupracující s databázi a MultiRouter taktéž.
MultiRouter bude napůl asociatiní a napůl seznam, kde položky se stringem v klíči bude možné extendovat,
dovolí mi to soustředit základní vzory (nebo vzory) na jedno místo a nemusím pak routy přepisovat v jednotlivých modulech, ale jenom si tam dám extend
V podsatě chcí mít routy s výchozím vzorem, které bude možné rozšířit.

příklad:

$router['default'] = new SiteRoute('/<language>/<node>', array(
  'language' => 'cz',
  'node' => Null
));


// vytvořím novou routu která bude obsahovat půvoní vzor, ale přiřadím si vlastní proměnnou
$router['default']->extend('/<category>/<articlename>'); # články
$router['default']->extend('/<date>/<gallery>'); # galerie

// v podstatě zjednodušené
$router[] = new SiteRoute('/<language>/<node>/<category>/<articlename>', array(
  'language' => 'cz',
  'node' => 'clanky'
));
  • metodě bude ještě nějak předávána vazba na presentery v Modification (viz níže)

Nedefinuji žádný presenter ani akce, protože to bude mít na starosti rozlišit router podle databáze,
budu mít díky tomu centralizované typy pohledů, ale jejich obsah bude dynamicky generovaný

Vytváření obsahu

Při vytváření obsahu si zvolím layout, který bude mít možnost náhledu.

  • Každý layout bude mít sockety, čili pomocí widgetů předepsané místa kam se budou dát vkládat addony a aktuální pohled
  • Když to bude layout dovolovat, jako například v dashboard, bude možnost poskládat si addony vedle sebe nb do více sloupců, zkrátka nastavit boxíky pomocí jQuery
  • zde bude potřeba postavit vrstvu nad latte, kvůli přepsání některých maker pro zobrazení náhledu
  • bude možnost specificky vybrat jaké komponenty zobrazit v socketech a jaké ne a jakým skupinám a uživatelům
    • podpora dědičnosti
  • na každý pohled bude možné navěsit addony a na některé addony další addony, čili podmíněné zobrazení. typickým příkladem jsou komentáře
Sockety (zásuvky v templatách)
  • 3 typy
    • pohled
    • addon
    • výčet addonů

Modulárnost

Základním principem bude kompletní modulárnost. Všechno budou moduly a bez nich systém nepojede.

Addony budou vizuální a nevizuální komponenty, které se nehodí pro hlavní obsah aktuálního pohledu

Modifications (to jméno jsem vymyslel v neděli ráno, nevyspalej 3km před domovem a už ani nevím proč se mi líbilo) budou přidávat možnosti typů stránek a jejich zobrazení

  • v administraci bude pomocí předávání „dummy routeru“ možné pozbírat vzory z jednotlivých modifikací

Rozdíl by mohl být jasný snad i z adresářové struktury

V třídě Kdyby bude přidána DRUHÁ implementace ServiceLocatoru, ta původní zůstane na klasické služby, druhá bude na načítání tohohle všeho.
Proto je v každé složce loader.php, v každém bude totiž vlastní implementace AddonLoader nebo ModificationLoader

class PaginatorAddon extends AddonLoader { }
class BlogModification extends ModificationLoader {  }

ModificationLoader bude vycházet z AddonLoaderu a bude přidávat některé funkčnosti (např pod-addony).

AddonLoader bude implementovat systém závislostí, kde záviset bude na textovém klíči přiřazeném na webu Kdyby.

  • klíč si uživatel bude moct vymyslet i svůj, ale katalogováním v databázi se klíče sjednotí
  • cachovat si bude AddonLocator, ale jen seznam nainstalovaných (=povolených) komponent, pohledy aj. bude načítat dynamicky
  • bude obsahovat metody pro inicializaci nebo potvrzení existence určitých součástí a řešeí závislotí na jiných komponentách
  • v proměnných třídy budou přesně vypsány vzory pro routery a k nim přiřazeny seznamy pohledů a budou přesně vypsány závislosti i pod-komponenty
Postup vytváření Addonu/Modifikace
  • rezervuji si klíč na webu pro svůj addon (vždy generuje systém)
  • klíč zapíšu do konstanty v třídě loaderu komponenty
  • nahraji archiv s komponentou na web a systém zkontroluje jestli v archivu je třída loader a v ní konstanta s příslušným klíčem
  • kliknu na „požádat o release“
  • admin zkontroluje a povolí uveřejnění
Příklad s BlogModification

komponenta bude vyžadovat nainstalovanou komponentu na komentáře což se bude potvrzovat už v loaderu, sama obsahuje třídy které z ní vychází, ale konkrétně implemetují jenom funkcionalitu svázání článku s výpisem komentářů, jinak by se všechny komentáře zobrazovaly u všech článků

Příklad s kontaktním formulářem

Typ obsahu může být například PageModification, čili…

  • v průvodci si vyberu vytvoření nové stránky
  • projdu pár nastavení
    • zařazování do stromu webu (díky Tharos)
  • vyberu si formičku pro obsah
    • možnost výběru
      • předdefinovaného layoutu (nesmazatelné)
      • vlastní layout
      • zkopírovat nastavení z jiné stránky a vytvořit tak závislost na právech pro její zobrazení (né na konkrétní stránce, s layoutem to nebude souviset, jenom se budou dědit a přepisovat práva pro jednotlivé sockety a komponenty na stránce)
        • dědičnost: práva po podstránku budou vždycky vycházet z rodiče a budou pouze přidávat důležitější pravidla
        • duplikace: můžu si zdědit a vytrhnout strom oprávnění po určitou úroveň ve stromu stránek a neporušit tak podstránky, ale zároveň změnit jejich rodiče. Čímž v podstatě smažu a přesunu stránku pod jiná oprávnění, ale neporuším potomky.
          • bude vyžadovat oddělené nezávislé stromy pro oprávnění zobrazení a strom stránek (tady bude docela punk-rock vyřešit konzistentnost)
      • vytvořit nový, nebo upravit stávající (nutnost editace layoutů, tohle ale nechci v DB)
    • layout bude možnost prohlídnout, překopat, přeorganizovat, uložit, skartovat, přepsat, podědit…
  • napíšu si obsah
    • ještě nevím jak to technicky vyřeším, ale v obsahu bude možnost vkládání addonů, čímž se vyhnu „samostatné stránce s jedním addonem typu kontaktní formulář“
  • uložím

Práva

  • systém rolí a práv
  • možnost specifického nastavení pro každého uživatele oprávnění v administraci
  • na frontendu budou „pouze“ role

To by měly být tak nějak v kostce základní principy. Když vymyslím něco nového nebo si na něco vzpomenu tak to sem přidám

// edit: přidán „Příklad s kontaktním formulářem“ jako reakce na Tharos

Poznámka překladatele: Fakt jsem tohle vymyslel, když jsem šel pěšky z vlaku 5km domů, s kocovinou, nevyspalý a sepsal ve 3 ráno z neděle a pondělí? :D

Editoval HosipLan (11. 3. 2011 19:32)

Tharos
Člen | 1030
+
0
-

Máš to vymyšlený hezky. U CMSek se mi líbí, že je opravdu spousta způsobů, jak systém pojmout a žádný není ten jediný správný. :) Jedno CMS na Nette mám napsané a při prohlížení Tvého konceptu si říkám: „Vida, tohle taky není až tak špatný nápad“ :). Osobně jsem šel trochu jinou cestou – možná cestou trochu menší modulárnosti. Jde o to, že můj výtvor je spíše takovým CMF (Content Management Framework), který mi sice umožňuje „sekat jako cvičky“ běžné webové prezentace s požadavky na kompletní správu (prostě produkt, který je ode mě v praxi nejčastěji vyžadován), ale nefunguje ale typem: do téhle složky nahraj moduly a ty pak zaktivuj. Což je možná nedostatek, kdo ví, jak to je ;).

Líbí se mi ten koncept on-fly vkládání modulů do stránky a držím palce – udělat to dobře nebude triviální. Tohle jsem pojal jednodušeji (hlavně z časových důvodů, měl jsem na vývoj toho systému omezený čas). Já mám v systému určitě typy stránek, které uživatel může vytvořit. Typem je například „Základní obsahová stránka“ či „Základní obsahová stránka s kontextovou fotogalerií“ a podobně. Ty typy jsou i s popisy, takže uživatel dobře ví, co ten či který typ znamená. Tvorba nové stránky se děje pomocí průvodce, kde prvním krokem je právě výběr typu stránky. V dalším kroku průvodce obsahuje většinou nějaké základní vlastnosti (umístění ve stromu webu, název stránky, SEO kraviny a podobně), v dalším pak definici hlavních obsahů, pak checkboxy s tím, které sdílené obsahy má stránka sdílet (jsou to různé postranní boxy a tak, každý typ stránky má přesně dáno, které obsahy může sdílet) a u speciálních typů je těch kroků více (například ta fotogalerie). Modifikace vypadá potom tak, že jsou ty jednotlivé kroky v tabech (záložkách).

Zní to hodně jednoduše, ale v praxi se to velmi osvědčilo. Je to velmi BFU friendl a běžné menší weby si vystačí s několika málo typy stránek. Pokud by počet typů stránek měl narůstat, dá se řada věcí přesunout do základních vlastností stránek (například zda na stránce zobrazovat kontaktní formulář a tak, nemusí být stránka typu „Stránka s kontaktním formulářem“).

Ale to on-fly umisťování komponent je samozřejmě hezčí a velmi se těším, jak se s tím popereš.

Mám jedno jediné doporučení – stanov si priority a milníky, při jejichž dosažení bude vždy nějaká plně funkční verze. Ono totiž to, co jsi napsal, je velký balík a budeš-li se snažit vše implementovat ve verzi „0.1“, riskuješ, že se to zase dostane do fáze mrtvého projektu… Třeba například vývoj Nelly IMHO tak nějak zamrzl (i když si netroufám říct, zda to je či není vyloženě mrtvý projekt) a je to škoda. Ale stává se to velmi snadno.

Hodně zdaru :).

Filip Procházka
Moderator | 4668
+
0
-

Díky díky díky za každé slovo :)

ad Nella: Vrták teď dělá svoje ORM což je vidět na jabber chatu, takže můžu potvrdit že nezamrzlo :)

ad „konktaktní formulář“: pohlédni si úpravy :) a díky za náměty k přemýšlení

ad taby s vytvářením: líbí se mi ten nápad se záložkami, ke krokovému formuláři bych určitě taky došel, protože nacpat všechno na jednu stránku by bylo trochu kacířské :)

ad doporučení: CMS Kdyby jsem skoro dokončil zhruba před rokem, ale pak jsem zjistil že je to strášná prasárna :D a jinak jsem ho dělal asi 3,5 roku, takže je to technicky vzato mrtvý projekt :D ale mám docela náladu na malé z mrtvých vstání :)

Tharos
Člen | 1030
+
0
-

No není zač :). Pro zajímavost poodkreji některé další vlastnosti mého systému, třeba by Tě ještě něco mohlo inspirovat. Zároveň si říkám, že bych taky mohl připravit alespoň nějaké demo. Pod volnou licencí ten projekt se ale prozatím uvolňovat nechystám – dalo by to spoustu práce (zdokumentování) a celkově vzato, podobné CMF beru už jako určitý kapitál :).

Routování

Takovým srdcem je router, který tahá stránky z databáze. Ty jsou uloženy jako traversal strom, kdy router je hledá podle URL. Ten můj má takovou vychytávku, že když stránku nenajde, snaží se ještě zjistit, zda adresa například „sluzby/ubytovani/galerie“ nevede náhodou na presenter stránky „sluzby/ubytovani“ a na view „galerie“ (prostě zkouší najít „sluzby/ubytovani“ a když tuhle stránku nalezne, vezme její presenter a view „galerie“). Umí to takhle zjišťovat až pro kombinaci <action>/<id>. Jaký to má smysl? Jde o to, že některé typy stránek mohou mít více view a odkazy na ně si samy generují. Dejme tomu, že uživatel založí stránku typu fotogalerie a nastaví jí URL „o-nas/fotogalerie“. Ten typ stránky má v databázi nastavený jako presenter „Fotogalerie“ a jako defaultní view například „default“. Na tenhle presenter a view povede URL „o-nas/fotogalerie“ (router samozřejmě předá presenteru i nějaké page ID). Ten typ stránky si ale automaticky umí vygenerovat i odkazy na například view „detail“ a podobně, dokonce umí vygenerovat i odkazy typu „o-nas/fotogalerie/detail/nejaka-fotogalerie“, což router zachytí a jako presenter nastaví zmíněný „Fotogalerie“, jako view „detail“ a předá ID „nejaka-fotogalerie“. Má to výhodu ve velké nadvládě na URL adresami, kamkoliv do stromu webu se dá umístit prakticky cokoliv.

Samozřejmě to přináší možnosti mnoha kolizí, ty jsou ale řešeny v adminu – při úpravě URL stránky se kontroluje, zda všechny její view náhodou nekolidují s nějakou jinou URL adresou (zkouší se normální match na databázovém routeru). Ta kontrola byla úděsná piplačka. :) Jinak každý typ stránky má v databázi nejen svůj presenter a defaulntí view, ale i informaci o tom, zda view může být „přetíženo“. Pokud ne (většina typů stránek), předchozí detekce view se vůbec neděje. Je to zbytečné /i když to vlastně jenom urychlí generování 404 :)/.

Presentery

Dlouho jsem přemýšlel, jak vhodně objektově reprezentovat stránku, až jsem nakonec skončil u toho, že nejlepší bude co nejvíc využít Nette a stránky jsou prostě reprezentovány presentery. Frontend je vcelku jednoduchý (jde jen o správné namapování routerem), v backendu to mám následovně: určitý typ stránky (reprezentovaný například presenterem Front_Fotogalerie) má svou analogii i v backendu (Admin_Pages_Fotogalerie). V adminu používám upravenou třídu Route tak, aby pobírala i submoduly (ta v Nette to bohužel neumí), takže v adminu mám presentery například pro různá nastavení (Admin_Settings), správu záhlaví a zápatí (Admin_GlobalContentsPresenter) atd. a velký submodul Pages s presentery pro všechny typy stránek. Pro každý typ lze pak nezávisle definovat, jakou přesně bude mít formu průvodce pro vytvoření stránky toho typu a jaké záložky budou pak dostupné pro editaci. Samozřejmě tam platí to, že základní kroky lze dědit z nějakého abstraktního předka, takže to není, že by se pro každý typ znovu definovaly všechny kroky i s formuláři. Je to docela DRY. :)

Výkon

Velmi doporučuji kešovat všemožné rekurze nad stromem webu a podobně. Věci jako generování globální navigace, kontextové navigace, drobků a podobně… Přestože se s použitím traversal stromu tahají z databáze poměrně efektivně, rekurzi se stejně člověk nevyhne (například pro převod stromu webu do multidimenzionálního pole) a ty rekurze jsou performance killer.

No, šlo by psát asi ještě dlouho :). Ale tak třeba z toho načerpáš nějakou inspiraci. Hodně zdaru přeju :).

na1k
Člen | 288
+
0
-

Líbí se mi, že se vedle Vrtáka našel ještě někdo, kdo se rozpovídal o svém CMS. Vždycky to s radostí čtu, protože je to krásná inspirace :)

Tady mi jen připadá, že chceš stvořit monstrum, které bude umět naprosto všechno. Neříkám že je to špatně, ale chci se zeptat – je to asi jen pro zábavu, co? Tím chci říct to, že vývoj něčeho takového sežere hromadu času, a tím vlastně i peněz. Samozřejmě je možné, že děláš v nějaké větší firmě, kde boucháte webové aplikace vyžadující plug'n'play moduly, hromady layoutů a jiné brutálnosti, ale mně to přijde spíš jako akademický projekt, kdy to se zájmem stvoříš, naučíš se na tom hromadu věcí, ale ve výsledku zjistíš, že to je jen těžkopádny nepoužitelný kolos. Ne že bych ti to přál, ale zajímá mě, jaký na to máš reálný pohled a hlavně co od toho očekáváš ;)

Můj CMS nad Nette je v celkem ranné fázi. Po delší době udržování jsem se s přechodem na 1.0 a php5.3 odhodlal k novému návrhu, ale hotovo ještě ani zdaleka nemám. Je to cílené na průměrné weby – klasicky kategorizované články, komentáře, galerie, newslettery + vždy něco extra pro konkrétní web, například uživatelská sekce, speciální správce souborů a jiné blbinky. Frontend pak tvoří jen několik málo presenterů a ty stejně jen provazují modely a šablony. Zbytek práce odvedou widgety. Z pohledu adresářové struktury nebo návrhu stromu presenterů se frontend vlastně nijak neliší od skeletonu. Můžu proto přijít (nebo kdokoliv jiný!), ignorovat backend a postavit třeba statický web nebo cokoliv jiného s naprostou volností a především „Nette Eleganc홓 :)

Síla ale přichází při zapojení backendu, který je pevně daný (designem a víceméně i funkčně) a schovává se ve složce libs. Obsahuje moduly (frontend defaultně žádné moduly nedefinuje) pro správu obsahu, které pak frontendu poskytují své služby (modely, továrny,…) pomocí speciální statické třídy – ta je pak jediná vazba, kterou může frontend použít.

Mám zahrnutý koncept událostí (např. modul přes celý backend „zakřičí“ že se chystá uložit článek, čehož se může chytit například nevizuální modul pro vyčištění html, obsah poupravit a vrátit původci události), závislosti mezi moduly (tam kde nestačí události a závislost je třeba vynutit) a aktuálně přemýšlím nad dělením moduly na nevizuální (poskytují jen obsluhy událostí a pomocné funkce) a vizuální (mají vlastní presentery pro backend). Tam ještě ale nemám jasno a případným tipům se bránit nebudu :)

Filip Procházka
Moderator | 4668
+
0
-

díky díky :)

ad routování: trochu jsem se v tom ztratil, ale v zásadě moje routování by mělo fungovat tak že základem bude ta <node>, popř další proměnná, která když bude splněna tak se to odkáže ve stromě výše při neshodě ostatních parametrů v ->extend() což by mělo být něco jako píšeš ty :)

ad presentery: stránka jako taková bude mít obsah v databázi, podle url se vybere <node> a přiřadí se presenter s pohledem a ten obsah zformátuje, url nebude ovládána jménem presenteru, ale uživatelem a vzorem jaký bude dovolovat Modification

ad výkon: s kešováním se počítá :)

Filip Procházka
Moderator | 4668
+
0
-

2 na1k:

díky za náměty k přemýšlení

Co se týče mého pohledu na věc, tak

  1. nikam nespěchám
  2. když nebudu celé dny sedět na facebooku a youtube tak odhaduju dobu vývoje na měsíc max dva

V žádné firmě nedělám, ted jsem dostudoval a mám moře času když nepočítám zakázky :)

Celé Kdyby samo o sobě bude jenom holá kostra s pár funkcemi na kontrolu obsahu, co bude tvořit obsah tak budou ty addony a modifikace a všechno to bude v databázi :)

Ani
Člen | 226
+
0
-

Tak já mám taky něco podbného ve výrobě (už asi rok :)), beží na tom i nějaké weby. Je to teda primárně zaměřené na malé živnostníky (bfu), takže to nemá, až tak pokročilé funkce.

Nicméně to mám řešené tak, že jednotlivé moduly (File, Page, Comment…), mají backend řešený jako presentry a Frontend přes komponenty. Kdy je pak jeden modul Frontend a v něm si pak tahám obsah přes ty komponenty z jednolivých backend modulů, takže třeba {widget menu:main} {widget page $id} atd. Jediné o co se stará frontPresenter je načíst slug z url a podle něj poslat id do šablony, případně prohodit šablonu.
Výhodný mi to přijde v tom že se pak dobře skládá jednotlivá stránka, když ma mít komentáře, tak zavolám widget stránky a widget komentářů… Ten Frontend se nemusí pak routovat do jednolivých modulů.

Co mi dělalo největší problém a pořád mi to nepřijde dobré je propojení modulů. Třeba když přidám modul na komentáře, tak chci do formu pro stránku přidat možnost povolení těch komentářů. Tak teď to řešim že se každý formulář odesílá do metody, kde se na něj podle jeho názvu navěsí další prvky (ty se načítají z jednolivých inicializačních tříd modulů (asi něco jako tvůj loader)) a callbacky na zpracování. Ale to mi přijde strašně kostrbaté, sice to funguje skutečně modulárně, ale nelíbí se mi to. Docela by mě zajímalo jak tohle plánuješ? Nebo prostě pro komentáře bude extra tamplate při vyběru?

Vzhledem k tomu, že ty uživatelé obsah moc často nemění se všechno co jde na frontend kešuje, pak se to nemusí připojovat k db a to je docela zrychlení, zvláště u některých hostingů to připojení do db vázne.

Edit:
Koukám že mám frontend řešený podobně jako na1k, to sem rád, možná to bude dobrá cesta :D

Editoval Ani (28. 6. 2010 14:25)

Filip Procházka
Moderator | 4668
+
0
-

[#8] Ani: Díky za reakci :)

Trochu hodně mě zmátl ten tvůj druhý odstavec :D

Do obsahu pohledu chci mít možnost navěšovat addony a na ně další pokud to budou umožňovat, snažil jsem se to popsat v příkladu s blogem

Ani
Člen | 226
+
0
-

No taky je to napsané pěkně pomateně, ale ono to takové ‚wtf‘ je, takže to jinak popsat nejde :D

Vlastně je to způsob řešení těch tvých adonů, kdy se jejich obsah vykresluje přes widget, který se automaticky vytvoří (v presentru i v šabloně). Z db se načte jejich seznam a v šabloně se vykreslí přes následujicí kód, díky tomu stačí univerzální šablona.

{if isset($hooks[$presenter->getName()])}
    <div class="content hook" n:foreach="$hooks[$presenter->getName()] as $hook">
        {var $c $hook['control']}
        {var $m $hook['metod']}
        {widget $c:$m $presenter->module, $id}
    </div>
{/if}

Zároveň se automaticky vytvoří ona komponenta v presentru pomocí podobné funkce.

Filip Procházka
Moderator | 4668
+
0
-

[#10] Ani: Podobně jsem to chtěl, jenom s tím že by se o to starala komponenta, která by měla sama podobnou templatu, potom bych jenom zavolal tu komponentu, s nějakým jednoduchým rozlišovacím slovím klíčem jako parametr, abych mohl rozlišit když jich budu mít v jedné templatě víc, potom si jenom v administraci přes upravený latte filtr přepíšu tyhle komponenty (teď mě napadá že bych ho snad ani nemusel upravovat) za jinou, která bude obsluhovat grafický vkládání a náhled a budu si to moct všechno v administraci „živě“ prohlídnout :)

Filip Procházka
Moderator | 4668
+
0
-

napíšu to ještě jednou sem pro případ že fórum necpe editace do RSS …

github: https://github.com/Kdyby
vyvíjet budu veřejně, licence bude nějaká open-source ve stylu „dělej si s tím co chceš“ takže můžete vesele kuchat :)

Editoval HosipLan (11. 3. 2011 19:31)

PJK
Člen | 70
+
0
-

Chtěl bych se zeptat jaké máš plány na správu/řešení rozšíření, které potřebují upravit databázi. (Hloupý příklad: Rozšíření, které bude počítat počty shlédnutí nějakých článků) Povolit modifikaci? Donutit všechna rozšíření vtořit vlastní tabulky/datové struktury? A jak jednu z těchto možností provést? Dovolit rozšíření nahradit původní entity modelu? Jak zajistit, aby se rozšíření nekolidovala?

Já jsem prozatím dospěl k tomu, že:

  • rozšíření = service / modul / komponenta
  • rozšíření může požadovat manuální nastavení (třeba spuštění „migrace“ databáze)
  • rozšíření si můžou říct o registraci vlastní „globální“ routy, tyto routy jsou spravovány managerem, který hlídá případné kolize a odmítá registraci (pak zbyde „sdílená“ routa)
  • rozšíření si musí svoje data spravovat sama, jediné, co můžou chtít, je připojení jejich entit ke společnému správci
  • základní entity a komponenty budou vydávat spoustu událostí, které mohou rozšíření zpracovávat (přemýšlím nad tím, jestli dovolit rozšířením po registraci i upravovat data (pak by rozšíření byly vlastně i filtry))
  • všechny metody a properties, které by rozšíření chtělo přidat entitě se musí popsat ručně ve stylu C# extension methods (budou jen syntaktický cukr)

Moje výhoda je v tom, že výsledek je určen pro programátory/vývojáře/skoro-programátory, takže si můžu dovolit víc než autor aplikací pro BFU.

Rady, komentáře, připomínky od zkušenějšího?

Filip Procházka
Moderator | 4668
+
0
-

Od zkušenějšího určitě radu nedostaneš, ale já ti k tomu svůj názor klidně řeknu. :)

V první řadě, tohle je otázka, která mě vůbec nenapadla. Napadlo mě, že může být více verzí stejného typu rozšíření/modulu (galerie, blog) a napadlo mě, že některá rozšíření by mohla vyžadovat instalaci specifické verze jiného rozšíření.

První co mě napadá, tak zasahovat do existující entity, to se mi vůbec nelíbí. Spíše bych uvažoval o využití Inheritance, nebo nějakého podobného nástroje, ale to je taky tfuj tfuj, protože bych mohl nainstalovat novější verzi některé závislosti a rozbít tim jiné věci. Je to velice komplikovaná otázka :)

Z hlediska editace a zásahů bych spíše volil možnost provazovat modely, nějak. Neměl by být problém napsat modelům konkrétního rozšíření interface a testy kompatibility.

rozšíření = service / modul / komponenta

Líbilo by se mi, kdyby každé rozšíření mělo nějaký instalátor, který by přijal instanci služby, která by se o rozšíření starala. Pomocí instalátoru by se nainstalovala/nakopírovala a tím bych měl i přehled nad tím, co se kam kopíruje a mohl tak rozšíření snadno hlídat.

rozšíření může požadovat manuální nastavení (třeba spuštění „migrace“ databáze)

Jo, proč ne

rozšíření si můžou říct o registraci vlastní „globální“ routy, tyto routy jsou spravovány managerem, který hlídá případné kolize a odmítá registraci (pak zbyde „sdílená“ routa)

Měl jsem myšlenku, která je už nějakej ten pátek rozpracovaná a ztratila prioritu, že v CMS bude instance pouze ExtendableRouteru a tento router by měl základní asi 2 nebo 3 vzory, které by jednoznačně odlišovaly url (section/node/url, node/url, url) a o vytvářené adresy by se starala administrace a hlídala by kolize.

rozšíření si musí svoje data spravovat sama, jediné, co můžou chtít, je připojení jejich entit ke společnému správci

Jsem pro možnost invalidace cache entit, který si ukládá doctrine a doplnění vyžadovaných struktur do databáze, ale raději bych viděl tabulky pro každé rozšíření vlastní, teoreticky by to tak mělo jít napsat vždy. Není přece problém napsat rozšíření, které bude kompletní fórum, eshop, …

základní entity a komponenty budou vydávat spoustu událostí, které mohou rozšíření zpracovávat (přemýšlím nad tím, jestli dovolit rozšířením po registraci i upravovat data (pak by rozšíření byly vlastně i filtry))

Doporučuji si přečíst o Symfonním Event dispatcheru který by mohl být šikovným pomocníkem :)

všechny metody a properties, které by rozšíření chtělo přidat entitě se musí popsat ručně ve stylu C# extension methods (budou jen syntaktický cukr)

Tohle se mi nelíbí, ale zavrhuji to z patra, protože není nikdo kdo by mlátil bastliče po prstech, že takhle a takhle to znásilňovat nemají. Zkrátka se mi nelíbí, že by dvě rozšíření, od různých autorů mohli jedno druhé rozšiřovat na takovéhle úrovni. Nějaký interface a testy kompatibility, ok. Ale přidávat data do existujících tabulek, „zpomalovat“ a zatěžovat tak existující rozšíření… Nevím, nevím, budu o tom ale přemýšlet.

Moje výhoda je v tom, že výsledek je určen pro programátory/vývojáře/skoro-programátory, takže si můžu dovolit víc než autor aplikací pro BFU.

Už tím, že používám Doctrine2, nepočítám, že by můj systém rozšiřoval nějaký BFU. Takže moje cílovka bude trochu jinde, ale skoro věřím tomu, že než zvládnu vydat něco použitelného, tak Patrik už mě dožene i s čísly verzí :))

PJK
Člen | 70
+
0
-

Měl jsem myšlenku, která je už nějakej ten pátek rozpracovaná a ztratila prioritu, že v CMS bude instance pouze ExtendableRouteru a tento router by měl základní asi 2 nebo 3 vzory, které by jednoznačně odlišovaly url (section/node/url, node/url, url) a o vytvářené adresy by se starala administrace a hlídala by kolize.

Pěkný, ale jak moc je to výkonný? Aby jenom dekódování routy vyžadovalo několik dotazů do db, to je docela peklo, ne? Nebo na to máš nějaký trik? Model\Node jsem v repu nenašel

rozšíření si musí svoje data spravovat sama, jediné, co můžou chtít, je připojení jejich entit ke společnému správci

Jsem pro možnost invalidace cache entit, který si ukládá doctrine a doplnění vyžadovaných struktur do databáze, ale raději bych viděl tabulky pro každé rozšíření vlastní, teoreticky by to tak mělo jít napsat vždy. Není přece problém napsat rozšíření, které bude kompletní fórum, eshop, …

Nó, tak jsem to myslel. Rozšíření si přinese svoje entity, uživatel spustí migraci a už to frčí

základní entity a komponenty budou vydávat spoustu událostí, které mohou rozšíření zpracovávat (přemýšlím nad tím, jestli dovolit rozšířením po registraci i upravovat data (pak by rozšíření byly vlastně i filtry))

Doporučuji si přečíst o Symfonním Event dispatcheru který by mohl být šikovným pomocníkem :)

Pěkné, díky

všechny metody a properties, které by rozšíření chtělo přidat entitě se musí popsat ručně ve stylu C# extension methods (budou jen syntaktický cukr)

Tohle se mi nelíbí, ale zavrhuji to z patra, protože není nikdo kdo by mlátil bastliče po prstech, že takhle a takhle to znásilňovat nemají. Zkrátka se mi nelíbí, že by dvě rozšíření, od různých autorů mohli jedno druhé rozšiřovat na takovéhle úrovni. Nějaký interface a testy kompatibility, ok. Ale přidávat data do existujících tabulek, „zpomalovat“ a zatěžovat tak existující rozšíření… Nevím, nevím, budu o tom ale přemýšlet.

To jsme se asi nepochopili… Naopak, tím že extension methods budou jen syntactic sugar a rozšíření si budou muset spravovat data sama se to výrazně pročistí (doufám). Opět příklad na počtu přečtení, jen nástřel z patra (ale nápad s anotacema se mi dost líbí):

<?php
class ArticleViewCount extends BaseEntity {
	protected $count;
	protected $articleId;
	//bla bla funkcionalita

	function getViewCount()
	{}

	/**
	* @extensionMethodTo(Core\Article)
	**/
	public static function articleGetViewCount(Article $artcile/*tady dalsi parametry*/) {
		$matchingEntity = self::$em->find(__CLASS__,$article->getId())->get();
		return $matchingEntity->getCount();
	}
}

//pak se zaregistrují všechny extension methody pro příslušné třídy

//a to umožní v šablonách nebo někde volat hezky pěkně
$article->getViewCount();
?>

Podle mě dost čísté, žádné bastlení… Pokud by se dvě rozšíření měla přebíjet, tak se to dozvíme a diagnostikujeme. Pak se to dá nějak řešit… třeba něco jako namespaces:

<?php
$article->extension('ViewCounter')->getViewCount();
?>

Hlavní je, že v tom bude pořádek (v rámci možností). Pak je samozřejmě ta možnost, že se to bude muset dělat ručně, ale to mě připadá přinejmenším silně otravné.
Situace: V šabloně loopuju result setem a vypisuju články. Teď jsem si nainstaloval to úžasné rozšíření na počítání slhlédnutí a chci to přidat v šabloně. Jak na to?

Buď v presenteru nějak přičaruju každému článku hodnotu z rozšíření (tfujtajxl, kvůli rozšíření musím šahat kamsi do presenterů???)

Nebo to budu dělat rovnou v šabloně, což ovšem bude vyžadovat něco stylu Dibi DataSource (nebo rovnou předat EM do šablony) a nebude to pěkné:

{$entityManager->find(ArticleViewCount,$article->getId())->get()->getViewCount()}
//nehezke, a co pak slozitejsi selecty?

//s extension methodami klasicky
{$article->getViewCount()}
//resp s bezpecnymi namespaces a shorthand magickými aliasy (jen nastrel)
{$article->viewCountExtension->getCount()}

A protože extension methods zachovávají zapouzdření původních entit, znásilňování se, holenkové, nekoná, bastliči si spálí prsty. Co na to říkáte?

Filip Procházka
Moderator | 4668
+
0
-

Pěkný, ale jak moc je to výkonný? Aby jenom dekódování routy vyžadovalo několik dotazů do db, to je docela peklo, ne? Nebo na to máš nějaký trik? Model\Node jsem v repu nenašel

Myslel jsem si, že to tam mám rozepsané (to Node tam není, protože je to jen rozpracované :)). Router pomocí základního vzoru najde v databázi Node, která bude jedním leaf/branch (stránkou/větví) struktury webu a zjistí, které další rozšíření má následovat (proto extendable).

$router['default'] = new ExtendableRoute('/<node>', array(
  'language' => 'cz',
  'node' => Null
));


// vytvořím novou routu která bude obsahovat půvoní vzor, ale přiřadím si vlastní proměnnou
$router['default']->extend('/<category>/<articlename>'); # články
$router['default']->extend('/<date>/<gallery>'); # galerie

// v podstatě zjednodušené
$router[] = new Route('/<language>/<node>/<category>/<articlename>', array(
  'language' => 'cz',
  'node' => 'clanky'
));

->extend by měly být nadefinované v jednotlivých rozšířeních. Mělo by tak jít zjistit jaké rozšíření použít a který extend má následovat a pak se zpracuje zbytek url. Teoreticky by to mělo být ještě rychlejší než současné routy, ale to bych spíš kecal, protože se musí provést do databáze, jehož výsledek rozhodne kudy pokačovat. Ale nemusí se porovnávat všechny routy, stačí identifikovat základní vzor a pak následovat rozšíření :) Část toho je hotová, ale chybí ještě constructUrl

$article->extension('ViewCounter')->getViewCount();

Tohle vypadá podstatně lépe :) ale pořád se mi na tom něco nelíbí, smrdí to magií a určitě to porušuje i nějaké OOP principy nebo návrhové vzory.

A máš pravdu, že příklad s počtem přečtení je opravdu nevhodný, protože mě napadá v tomhle případě lepší řešení :) Něco jako:

Počet přečtení: {control viewCounter:views $article}

Což by se přeložilo jako

echo $control->getWidget('viewCounter')->renderViews($article);
PJK
Člen | 70
+
0
-

K routám: Neuvěřím dokud neuvidím. Osobně pochybuju o tom, že to kdy může být rychlejší než klasické routy. V db může být i klasický pattern, ne? Takže práce je klasické matchování + získání stromu cest.

HosipLan napsal(a):

$article->extension('ViewCounter')->getViewCount();

Tohle vypadá podstatně lépe :) ale pořád se mi na tom něco nelíbí, smrdí to magií a určitě to porušuje i nějaké OOP principy nebo návrhové vzory.

Návrhový vzor sem, návrhový vzor tam, mně je všechno rovno. Oblíbenou hru „zakomponuj si co nejvíc cool návrhových vzorů a pak metej jejich obfuskované názvy po všem, co se pohne“ nehraju. Úroveň magické energie malá, určitě pod hranicí nebezpečnosti. A které principy OOP že to porušuje? :)

A máš pravdu, že příklad s počtem přečtení je opravdu nevhodný, protože mě napadá v tomhle případě lepší řešení :) Něco jako:

Počet přečtení: {control viewCounter:views $article}

Což by se přeložilo jako

echo $control->getWidget('viewCounter')->renderViews($article);

Svatá pravda. To je dobrá připomínka. I když ono je to v podstatě totéž jako ty extension methods, zamysli se nad tím :P. A já se nad tím taky zamyslím :).

http://msdn.microsoft.com/…b383977.aspx

Filip Procházka
Moderator | 4668
+
0
-

Když máš 50 rout, které musíš vyhodnotit a platí až ta poslední a 3 routy, které se matchnou provedou superrychlý dotaz do databáze a máš okamžitě výsledek, myslím že to bude víc než srovnatelné :) Samozřejmě, výhoda tohohle přístupu se objeví až s narůstajícím počtem stránek a typů rout.

Návrhový vzor sem, návrhový vzor tam, mně je všechno rovno…

To není žádná hra, ale princip, který se nevyplácí porušovat :) Já nevím, prostě se mi na tom něco nelíbí, ale ještě jsem nepřišel na to, co.

JakubJarabica
Gold Partner | 184
+
0
-

Ono aj tá databáza bude čoskoro s návštevnosťou problém. A robiť pri routovaní „zbytočné“ SQL dotazy nie je podľa mňa ideálne. Skôr si narobiť nejakú rozumnú cache, ktorá by sa napratala do Memcache, a až keby sa tam nepochodí by som šahal do DB(ak v Memcache sa nič nenájde – či naozaj 404ku alebo ak bol nejaký problém, aby bol fallback do DB).