YetORM – kvaziORM nad Nette\Database
- uestla
- Backer | 799
Ahoj.
YetORM
Spojuje mapování na objekty a efektivitu dotazů
Nette\Database
.
Skládá se ze 3 tříd:
Repository
– stará se o svoje entity – načítá, vrací instance, ukládá…Entity
– kompozicí dostává instanciActiveRow
. Její API je čistě na nás.EntityCollection
– lazy kolekce entit na stylSelection
, tedy až při foreach nebo na zavolánítoArray()
načte data a namapuje na entity. Do té doby můžeme kolekci řadit a limitovat, aniž by se provedl jediný dotaz.
Uváživše hořejší a vybavivše si ukázkový příklad z dokumentace, přepíši jej následujícně:
$books = new BookRepository($context);
foreach ($books->findAll() as $book) { // $book instanceof Book
$author = $book->getAuthor(); // instanceof Author
echo $book->getTitle(), " (", $author->getName(), ")";
foreach ($book->getTags() as $tag) { // $tag instanceof Tag
echo $tag->getName(), ", ";
}
}
Dotazy se položí naprosto ve stejném provedení jako při nativním
volání Nette\Database
.
Rozhraní BookRepository
, entity Book
,
Author
a Tag
vč. jejich metod, je to, co si člověk
musí vyrobit sám. K dispozici je ale API pro zvládnutí všech relací 1:N
i M:N.
Např. Book
vypadá zhruba takto:
class Book extends YetORM\Entity
{
/** @return string */
function getTitle()
{
return $this->record->title;
}
/** @return Author */
function getAuthor()
{
return new Author($this->record->author);
}
/** @return YetORM\EntityCollection */
function getTags()
{
$selection = $this->record->related('book_tag');
return new YetORM\EntityCollection($selection, 'Tag', 'tag');
}
}
Sources
GitHub – zdrojáky vč. testů, ze kterých to snad půjde lépe vyčíst.
Díky předem za nenávistné komentáře.
Editoval uestla (25. 5. 2014 15:15)
- llook
- Člen | 407
Líbí se mi, jak je to jednoduché. Používám totiž ORM, které toho umí asi 10× víc, ale někdy je docela hukot se v tom vyznat a beztak většinou využijete jenom ten základ.
Ale to nezní moc nenávistně… takže mi tady schází hlavně tyto věci:
- Magie, aby člověk nemusel pořád copypastovat ty pořád stejné
[gs]ettery. Co třeba
@property
,@property-read
apod.? - High-end CRUD operace, které by dělaly v podstatě totéž, co ty low-end, co tam jsou, ale proháněly by ta data přes entity, takže by na nich fungovala validace, custom setters atp.
- Taky si nejsem jistý tou metodou rollback(). Přidal bych kontrolu, jestli $transactionCounter === 1, jinak exception.
- redhead
- Člen | 1313
Taky se mi to moc líbí. Díky!
Zrovna jsem to nasadil na nově zrefaktorovanej model a fakt hezky se to používá, na to jak je to jednoduché.
Ještě by se mi líbil nějaký lepší způsob ukládání, abych nepředával entitu a k ní hodnoty. Snad by mělo fungovat následující:
$book = $repository->getById(5);
$book->setTitle('Mistrovství v PHP5'); // $this->row->title = $title;
$repository->update($book); // $book->getActiveRecord()->update();
Nebo mi něco ušlo?
Editoval redhead (10. 2. 2013 22:34)
- uestla
- Backer | 799
Na llookův popud jsem (zatím v boční branchi) přidal podporu pro anotace nahrazující primitivní gettery a settery.
Podporované jsou @property
pro getter i setter a
@property-read
pro getter. Anotace je třeba zapsat kompletně, tj.
i s typem, na který se hodnota přetypuje. Anotací lze využít jen pro
primitivní datové typy.
Následující definice entity jsou ekvivalentní:
EDIT:
Místo předchozího přetypovávání se nyní striktně kontroluje typ, jinak se vyhodí výjimka (podle toho jsem i upravil kód níže).
- ruční gettery/settery
class Book extends YetORM\Entity
{
function getId()
{
return (int) $this->row->id;
}
function getTitle()
{
return (string) $this->row->title;
}
function setTitle($title)
{
if (!is_string($title)) {
throw new Nette\InvalidArgumentException("Invalid type - 'string' expected, '" . gettype($title) . "' given.");
}
$this->row->title = $title;
return $this;
}
}
- využití anotací
/**
* @property-read int $id
* @property string $title
*/
class Book extends YetORM\Entity
{}
Interně se tedy properties nastavují instanci ActiveRow
spjaté s instancí entity. Pokud je zároveň definována anotace spolu
s ručním [gs]etterem, přednost má ruční definice. Stejně tak je
upřednostňováno výchozí Nette\Object
properties chování.
Při volání [gs]et<Property>()
se převádí z CamelCase
na podtržítkové jméno.
Příklady:
$book->setTitle('Book title'); // ekvivalentní s $book->title = 'Book title';
$title = $book->getTitle(); // ekvivalentní s $book->title
$book->setId(123); // zhavaruje, $id je read-only
Editoval uestla (1. 4. 2013 17:51)
- uestla
- Backer | 799
@castamir: Popravdě nevím, k čemu by to bylo
dobré. Když má entita závislost ve více tabulkách, mělo by být možné
si pro tuto závislost sahnout čistě přes API ActiveRow
.
Jinak jsem properties nakonec mergnul do masteru + přidal možnost zapsat
pomocí anotace entitní třídu a tabulku (obojí se doteď bralo buď
z definované proměnné třídy, případně z názvu
*Repository
, pokud tato neexistovala).
- Šaman
- Člen | 2661
Jen poznámka k těm anotacím. Ačkoliv v PHPDoc anotacích používám
jako typ proměnné název třídy, tak u definování property je nutné
použít slovo 'object'
.
Při zpracování těch properties se totiž typ prožene přes funkci
'settype'
, který název třídy neumí zpracovat, slovo
object ano.
A díky za tento miniORM, je to tak malý, že chápu zdrojáky a přitom to
umí generovat objekty. Mám v tom teď zpracovaný ukázkový příklad se
všemi druhy vazeb a poprvé od opuštění Dibi mě databáze (moc) neděsí
:)
..ooOO(I když s tím souvisí i dvě nocovky nad čistou Nette\Database)
Edit: Nechceš ho dát do doplňků? I jako beta verzi? Jinak časem odroluje v diskuzi a kdo si na něj nevzpomene, ten už ho nenajde.
Editoval Šaman (5. 3. 2013 7:10)
- Tharos
- Člen | 1030
Ahoj,
tak jsem si s YetORM dneska hrál „naostro“ a pracovalo se mi s ním opravdu výborně. Využít kompozice a takto zapouzdřit ActiveRow považuji za skvělý nápad. Přesně takhle si představuji ORM vrstvu – tenká, ale principiálně nijak neomezená.
Protože jsi mi tímto dílem ušetřil nemálo času :), rád bych také věnoval nějaký svůj čas pro něj. Chci se Tě zeptat, co bys nejvíce ocenil.
Napadla mě třeba nějaká ukázková aplikace včetně doprovodného článku… Model by v ní byl kompletně zapouzdřený pomocí servisní vrstvy s YetORM pod pokličkou – vůbec by to mohla být hezká ukázka určitého stylu, jakým lze v Nette vyvíjet. Co si o tom myslíš? Zadání bych si vymyslel takové, aby v něm existovala „netriviální doménová logika“ (taková, kterou nelze pokrýt klíči v databázi…).
A pak jsem se Tě chtěl zeptat, jakým směrem plánuješ vývoj směřovat
a jestli bych taky třeba časem mohl poprosil o Composer balíček. :) Anebo
to zkusit protlačit přímo do Nette (jmenný prostor
Nette\Database\ORM
by těm třem třídám určitě slušel).
Zkoumal jsem více modelů nad Nette\Database a nic mě neoslovilo, dokud jsi nenapsal tohle. Ještě jednou díky :).
- uestla
- Backer | 799
To mě těší. Komunitnímu vývoji se absolutně nebráním, čili
pokud
chce kdokoli čímkoli přispět, jsem jedině pro.
Co se composeru týče, s tím pořád nejsem kamarád, používá-li
někdo YetORM a kamarádí se s composerem, budu rád za pullík.
A k budoucímu vývoji: právě se snažím rozumně rozšířit
properties,
aby šlo deklarovat i typ coby třídu (čili rozšířit současný stav,
kdy jsou podporovány pouze primitivní datové typy).
Pokud mně, nebo někomu jinému, bude při používání chybět
nějaká
funkcionalita, klidně to můžeme prodiskutovat a přidat, není problém.
Zatím jsem to použil asi 3krát, a celkem mi to vyhovuje.
Těší mě, že to někomu pomůže, nicméně zdržel bych se zatím
názorů o zařazení přímo do Nette, na to je to ještě v moc raném
stádiu a připouštím, že to má i nějaké mouchy (viz výše).
Díky!
- thunderbuff
- Člen | 164
Tak jsem YetORM zkusil. Musím říct, že je to opravdu krásná práce! Jak říká Šaman, je to tak minimalistické, že zdrojáky jdou lehce pochopit a přitom to krásně funguje. Palec nahoru :-)
- uestla
- Backer | 799
Na Šamanův
popud jsem v properties
branchi experimentálně přidal
podporu pro třídní property typy. Nicméně využití to najde nejspíš jen
u datumu,
protože jiné instance (nepočítám-li
ActiveRow
) nativní přiřazování u
ActiveRow
pokud vím nezvládá, ale budiž…
Upravil jsem podle toho testy.
Editoval uestla (31. 3. 2013 16:29)
- mkoubik
- Člen | 728
uestla napsal(a):
Co se composeru týče, s tím pořád nejsem kamarád, používá-li
někdo YetORM a kamarádí se s composerem, budu rád za pullík.
Pullík, přidej si tam
akorát "license": "..."
a zaregistruj si to na https://packagist.org/.
A ještě by to asi chtělo upravit testy, aby používaly Nette a PHPUnit z composeru.
Editoval mkoubik (31. 3. 2013 14:46)
- Tharos
- Člen | 1030
Tak jsem si taky dovolil poslat jeden pull request.
Provedl jsem drobnou optimalizaci: doteď se u entit při každém přístupu k položce přes magické metody __get nebo __set vytvářela nová reflexe, což je v PHP relativně drahé. Nově se jednou vytvořené reflexe uchovávají v paměti.
Editoval Tharos (31. 3. 2013 21:25)
- Tharos
- Člen | 1030
Ahoj,
narazil jsem na jednu věc, která mi aktuálně vcelku dost chybí. Než ale pošlu pull request, chtěl bych to probrat ještě tady…
Mějme propertu Entity zapsanou přes anotaci, která může nabývat hodnoty
null
. V anotaci by se to pak standardně zapsalo jako
string|null
, null|string
, string|NULL
,
nebo NULL|string
. S tím si teď ale ORM neporadí.
Nejjednodušším možným řešením je prostě kontrolovat, jak typ
začíná nebo končí, a podle toho null
hodnoty povolit. Problém
je, že si to ale neporadí třeba se zápisy string|null|bool
.
Otázka je, zda takové zápisy mají vůbec smysl? Byť jsou syntakticky
správné. Problém by s nimi byl samozřejmě i u automatického __set, kde
by ORM nevědělo, na který typ vlastně přetypovávat.
To nejjednodušší řešení mám naimplementované a mohu poslat. Pokud bys ale chtěl něco sofistikovanějšího, dej vědět.
Editoval Tharos (2. 4. 2013 10:13)
- uestla
- Backer | 799
Dobrý postřeh, databáze NULL
vracet může, to je pravda.
Smysl mi ale dává pouze <type>|NULL
, všude jinde bych
striktně trval na typu jediném – nejen z důvodu, že by knihovna
nevěděla, na co přetypovávat, ale hlavně kvůli udržení aspoň nějaké
konzistence. Nevidím důvod, proč by jedna properta měla nabývat dvou
různých neNULLových typů.
- Tharos
- Člen | 1030
Vidím to úplně stejně. Mám teda připravit pull?
Spolu s tím bych rád vyzkoušel i dekomponování parsování těch
property anotací do samostatné třídy (např.
YetORM\EntityReflection extends Nette\Reflection\ClassType
). Mělo
by to několik výhod: parsování anotací by proběhlo zase jenom jednou a ne
při každém přístupu k __get/__set, šlo by pak odstranit ty (IMHO
ošklivé) výstupní parametry (&) a spolu s tím by šlo hezky vyřešit
i problém s null
.
No, já to u sebe takhle připravím a pak uvidíš, jestli to bude kompatibilní s Tvými představami. :)
Editoval Tharos (2. 4. 2013 13:29)
- Tharos
- Člen | 1030
Tak jsem si s tím pohrál a výsledek můžeš vidět v téhle mojí brenši. Jelikož to byl poměrně hluboký zásah, pull request zatím neposílám. :)
Tak nějak by to mělo řešit vše, o čem jsem psal ve svém předchozím postu…
No ale mám v tom i jeden BC break. Vypustil jsem to automatické
přejmenovávání názvu fieldName → field_name, protože
já v databázi sloupce pojmenovávám lower-CamelCasem (například
bookTitle
) a přes tu Tvou konverzi u mě nejel vlak. :)
Podtržítko používám pouze u sloupců, které nesou cizí klíč
(například author_id
).
Nabízím, že tam ten převod doplním jako nějaký adaptér. Zkrátka si
myslím, že podobná konverze by měla být spíš snadno doplnitelná a ne
zadrátovaná v core kódu. Já jsem si kvůli tomu pro své
bookTitle
sloupce musel psát get/set metody…
Dej vědět, co si těch mých úpravách myslíš a pokud by Ti to vyhovovalo, pošlu pull request.
Editoval Tharos (2. 4. 2013 23:28)
- uestla
- Backer | 799
Ahoj, předně chci poděkovat – koukal jsem na brenš a vypadá moc pěkně. V souvislosti s vyčleněním reflexe bych možná zvážil ještě začlenit podporu pro třídní typy propert, co mám teď v branchi properties.
Ohledně adaptéru – přemýšlel jsem nad tím, ale nedošel jsem k použitelnému řešení. Takový adaptér by byl spjat s entitou, která se ovšem vytváří ve všech 3 vrstvách (entita, kolekce, repozitář). Otázka je, na které vrstvě tenhle adaptér nastavovat. Globálně nastavit pro danou entitu mi přijde nešťastné.
- Tharos
- Člen | 1030
Nemáš zač, pořád se cítím dlužníkem. :)
Ad adaptér) Napadlo mě ještě jedno řešení, úplně snadné:
/**
* @property string|null $bookTitle %book_title
*/
class Book extends YetORM\Entity
{
}
Prostě by se vymyslela syntaxe pro zápis názvu sloupce tabulky (pokud se liší od názvu property) přímo v anotaci. Co si o tom myslíš? Implementačně triviální a snad vše řešící.
Ad třidní properties) To by mělo být to nejmenší.
Refaktoruji do YetORMu jednu menší aplikaci, která má ale poměrně košatý model. Beru to jako takový křest ohněm. :) Zatím to jde hladce a postupně mi krystalizují na povrch všemožné drobnosti, které za běhu v ORM ladím. Mimochodem povedlo se mi vcelku snadno namapovat jednu entitu rozlezlou do více tabulek – do jedné „hlavní“ a jedné „doplňkové“, a to ještě tak speciálně, že pro některé entity záznam v té doplňkové tabulce vůbec nemusí být. Tohle se mi zatím s žádným jiným ORMkem tak elegantně namapovat nepodařilo. :)
Až si dohraji, udělal bych z toho nějaký závěr a připravil bych pull request. Kód udržuji minimální, za sebe bych byl opravdu nerad, aby ORM nějak kynulo. Sepíšu, co a proč jsem upravil a pak nechám na Tobě, jestli to začleníš.
- uestla
- Backer | 799
To je suprovej nápad! Protože property zápis vlastně supluje vlastní [gs]ettery, ve kterých si to člověk napíše ručně, očekávalo by se, že se podobná věc bude řešit přímo v zápisu propert. A já vůl už bych to právě hnal kynoucí cestou.
Osobně bych taky byl raději za udržení minimaličnosti…
Pokud to github umí, forknu si tvůj fork a pošlu ti pull requesty s drobnostmi, na které jsem narazil, a pak bychom to mohli zařadit do masteru. Nezapomeň se ale prosím uvádět jako autor u toho, co napíšeš, ať je v tom pořádek.
Díky!
- Tharos
- Člen | 1030
Ahoj,
tak jsem k sobě pushnull ty mé nedávné úpravy. Teď jsou ve větvi dev, tu EntityReflection jsem už u sebe začlenil do masteru. Stručně k mým změnám a k tomu, co mě k nim vedlo:
Drobné rozšíření EntityReflection
Nově umí jednorázově
zmapovat settery a gettery. Logicky to do této třídy patří a dá se
toho využívat v Entity::toArray (viz dále) a také v Entity::checkValidity
(viz dále).
Přidána metoda Entity::checkValidity
Metoda, která se z entity pokusí postupně načíst všechny položky a
u těch, které nejsou read-only, je na ty hodnoty opět nastaví (stav se tedy
nijak nezmění). Pěknej nesmysl, že jo. :) Ale jen na první pohled. Díky
této akci protečou zapouzdřená data skrze všechny gettery a settery a
vyhodí se výjimka, pokud je někde nějaká nekonzistence. Využívám toho
hlavně při vytváření
záznamů.
Upravena metoda toArray()
Nebavilo mě ji pro každou entitu s vazbami upravovat. Nyní si poradí
i s navázanými entitami a kolekcemi entit – jednu úroveň vypíše
kompletní, další úrovně jen informativně. Hezky je to vidět
v testech. To, že se hlubší úrovně vypisují jen informativně,
řeší problém s kruhovými závislostmi při konverzi.
Přejmenována metoda toActiveRow
Tohle je taková otázka. Úspěšně mapuji v jednom případě dvě tabulky
(1:1) do jedné entity a když taková entita podědí metodu toActiveRow, je to
divné, protože ona v sobě zapouzdřuje dvě instance ActiveRow
.
Přemýšlel jsem, na co by to šlo přejmenovat a vyzkoušel jsem
decapsulate
. :) Název vychází z toho, že entita zapouzdřuje
(encapsulates) nějakou vnitří reprezentaci (typicky jeden ActiveRow) a pro
pár speciálních účelů (persistence, výmaz) je výhodné tu vnitřní
reprezentaci dostat ven. Decapsulate mi přišel vhodný termín :). Ale tohle
je určitě k diskuzi, vím, že to není obvyklé sloveso.
Tak si to projdi… Snažil jsem se dodržet coding style a testy samozřejmě procházejí (samozřejmě jsem je vhodně upravil, hlavně aby reflektovali úpravy v toActiveRow). Kdyby se Ti to celé líbilo, klidně můžu poslat pull request. :)
Jinak ve volných chvílích bych tedy ještě doimplementoval tu možnost definice názvu sloupce u property a také podporu pro „hintování“ ostatních entit. Pak bych taky dopsal testy pro té mé nové funkce.
Pak by to bylo z mého pohledu úplně dokonalé :).
Editoval Tharos (5. 4. 2013 22:48)
- enumag
- Člen | 2118
@uestla, @Tharos: V posledních verzích 2.1-dev je ActiveRow::__set() deprecated, nebude to vyžadovat určité změny?
- Tharos
- Člen | 1030
Hmm, tak to je hezký… Pokud se přejde ze __set
na
update()
, elegantní persistence půjde do kytek. Při zachování
současného stylu by se pak musela ukládat každá změna samostatně…
takže pytel dotazů kvůli jedné entitě.
Takže pevně doufám, že se ta změna nakonec z 2.1-dev vypustí…
Edit: Prošel jsem si bleskově debatu na GitHubu a asi nevidím úplně do detailů Nette\Database… Dá se v pár větách shrnout, co je na těch metodách špatného a proč by měly být deprecated?
Editoval Tharos (6. 4. 2013 0:00)
- uestla
- Backer | 799
Stavíme-li na něčem, co je v „divokém“ vývoji, asi bychom s tím
měli počítat… Update se volá z Repository
, čili bude to sice
psaní navíc (možná nějaký podobný mechanismus jako býval v
ActiveRow::__set()
půjde převzít), ale fatální by to být
nemělo… Ať už bude entita spojovat jednu nebo více tabulek…
- Tharos
- Člen | 1030
No, po pár minutách úvah mi také přijde, že tragické to nebude…
Nejsnazší a vyhovující by mohlo být prosté zabalení ještě
i samotného ActiveRowu do tenké obálky, která by pak na něj většinu
volání přímo delegovala (všechny read operace) a sama by se zapojovala
jenom do řešení těch write. Edit: Nejspíš to půjde
i jednodušeji.
@hrach: Já chápu, co tím myslíš. Nicméně musíš uznat, že naše využití bylo praktické. :) Prostě u podobných věcí je třeba vědět, co se dělá, a pak se jich dá výhodně využít. Nový přístup bude určitě blbuvzdornější, ale prostě nějakou režii s sebou ponese.
V každém případě díky za odezvu.
Editoval Tharos (6. 4. 2013 7:25)
- enumag
- Člen | 2118
@Tharos
Přejmenována metoda toActiveRow
Tohle je taková otázka. Úspěšně mapuji v jednom případě dvě tabulky (1:1) do jedné entity a když taková entita podědí metodu toActiveRow, je to divné, protože ona v sobě zapouzdřuje dvě instanceActiveRow
. Přemýšlel jsem, na co by to šlo přejmenovat a vyzkoušel jsemdecapsulate
. :) Název vychází z toho, že entita zapouzdřuje (encapsulates) nějakou vnitří reprezentaci (typicky jeden ActiveRow) a pro pár speciálních účelů (persistence, výmaz) je výhodné tu vnitřní reprezentaci dostat ven. Decapsulate mi přišel vhodný termín :). Ale tohle je určitě k diskuzi, vím, že to není obvyklé sloveso.
S tímhle mám trochu problém – jestli to dobře chápu tak v tvém případě metoda decapsulate u té entity co zapouzdřuje dva ActiveRow vrací něco jiného, což je špatně. Metoda by měla vždy vracet stejný typ. Samozřejmě pokud vrací tvou vlastní implementaci Nette\Database\Table\IRow, je vše v pořádku.
- uestla
- Backer | 799
Zatím se spíše inspiruji. Snažím se nedělat zbytečně moc razantní změny…
Ohledně Reflection jsem šel podobnou cestou – vznikla
branch reflection, ve
které přibyl namespace Reflection
sdružující logiku propert
(na to, že jde o alternativní funkcionalitu týkající se zápisu anotací,
to vyhřezlo celkem pěkně :-) ).
Přidal jsem tam rovnou i podporu zápisu jména sloupce, funguje takto:
/** @property string $bookTitle -> book_title */
class Book extends YetORM\Entity
{}
Díky tomuto zápisu pak mohu používat následovně:
$book->bookTitle = 'title'; // odpovídá $book->row->book_title = 'title'
Do téhle větve bych přidal podporu pro třídní typy z properties větve. No a až přijde správná chvíle, tak to hodím do masteru.
- castamir
- Člen | 629
Již delší dobu si dělám vlastní ORM nad dibi (nechtěl jsem znásilňovat nette/database + předělávat značnou část logiky díky query dotazům, které vrací Row a ne ActiveRow). Zpracování properties mám v konstruktoru resp metody volané v kostruktoru. Pro každou třídu entit se provede právě jedno namapování. Logika properties je oddělená ve vlastní třídě Property, zatímco v Entity odpadne spousta zbytečného kódu. Při nastavení hodnoty testuju existenci podle aliasu (bookTitle pro book_title) a pak přímým přístupem získám property, na kterým jen zavolám validate. Ještě mi tam toho spousta chybí (mapování všech databázových typů na hodnoty a třeba správná práce s výčtovým, setovým či datovým typem, ale princip je snad dobře viditelný.
- Vojtěch Dobeš
- Gold Partner | 1316
<offtopic>
@castamir Musím se zde PetrOrmu zastat, jde
o výborně navržený nástroj, který je především flexibilní (!), a
zároveň se s ním dá de facto rychle prototypovat.
Dokumentace bohužel neexistuje v ucelené formě, ale velké množství detailně popsaných informací přímo od autora lze najít na fóru.
Ad nedokončené: za to je profesionálně vyvíjené s extrémním důrazem
na zpětnou kompatibilitu.
</offtopic>
Editoval vojtech.dobes (7. 4. 2013 12:05)
- uestla
- Backer | 799
Právě jsem mergnul reflection do masteru – což způsobilo BC break
u defaultní propertyName
⇒ column_name
konverze – tu je případně třeba dělat ručně (příklad výše).
Co se nekompatibility s Nette-2.1-dev
ActiveRow::update()
týče, zatím úpravy zařazovat neplánuji,
mám rozpracovaný pokus, ale vzhledem k větším odlišnostem
(SelectionFactory
, apod.) a možnosti dalších změn ještě
s jakoukoli finalizací počkám…
Souhrn změn oproti předchozí „verzi“ masteru:
- podpora třídních typů v properties (např.
@property DateTime $written
) - podpora NULL typu v properties (
<type>|NULL
)
Velké díky Tharosovi za přispění!
Editoval uestla (9. 4. 2013 14:10)
- Jack06
- Člen | 168
Taková technická.
Zkusil jsem si to implementovat v podobě example a přidal jsem si namespace
(modulová aplikace).
Ve chvíli, kdy jsem to vše dal pod společný namespace, tak mi to vyhazuje chybu u metoda toArray typ tabulky M:N. Nešlo by implementovt aby si to přebralo namespace? Nebo to jedině psát ručně do vztahu?
/* struktura stejná jako tagy */
$return['sections'] = array();
foreach ($this->getSections() as $section) {
$return['sections'][] = $section->getName();
}
Vyhozená chyba pak je: Class ‚Section‘ not found
Přičemž existuje, ale je v nějakém namespace, stejném jako ‚entita‘,
ze které se to pokousím volat.
Section.php – http://pastebin.com/kXNdEpUk
Article.php – http://pastebin.com/MxKRYKUd
Fatal error File: …\libs\YetORM\EntityCollection.php Line: 71 – http://pastebin.com/LkfvjwKJ
Editoval Jack06 (14. 4. 2013 12:50)
- Jan Tvrdík
- Nette guru | 2595
@Jack06: Zkus upravit getSections()
:
/** @return \YetORM\EntityCollection */
public function getSections()
{
return $this->getMany('ArticleModule\Section', 'article_has_section', 'section');
}
Brát to relativně by vedlo k hromadě problémů. Možná tě potěší, že v PHP 5.5 už půjde napsat
/** @return \YetORM\EntityCollection */
public function getSections()
{
return $this->getMany(Section::class, 'article_has_section', 'section');
}
- Jack06
- Člen | 168
Jan Tvrdík napsal(a):
@Jack06: Zkus upravit
getSections()
:/** @return \YetORM\EntityCollection */ public function getSections() { return $this->getMany('ArticleModule\Section', 'article_has_section', 'section'); }
Brát to relativně by vedlo k hromadě problémů. Možná tě potěší, že v PHP 5.5 už půjde napsat
/** @return \YetORM\EntityCollection */ public function getSections() { return $this->getMany(Section::class, 'article_has_section', 'section'); }
Super, to bude přesně to co chci :-)