Oznámení
před 5 lety
- Tharos
- Člen | 1042
@jannek19: Ahoj, je více možností, jak tohle vyřešit. V MySQL databázi bych to já řešit asi tak, že bych měl ten sloupec nadefinovaný takto:
created DATETIME DEFAULT CURRENT_TIMESTAMP
Property bych pak měl read only a vůbec ji ručně nenastavoval. Bohužel výše uvedená definice funguje asi až od MySQL 5.6.5…
Jinak bych to asi řešil v repositáři přetížením protected metody
Repository::insertIntoDatabase
. Na entitě bych tu položku měl
opět nadefinovanou jako read only a v té přetížené metodě
v repositáři bych tu hodnotu doplňoval. V podstatě bych si tu miniaturní
metodu (má 6 řádků) napsal pro relevantní typ entit nanovo.
před 5 lety
- janpecha
- Člen | 58
Ahoj, protože už mě fakt nebaví prohrabávat toto vlákno, tak jsem si dneska začal psát takovou vlastní „dokumentaci“ k LeanMapperu. Prozatím je to stále ve stádiu tvorby, hotová je základní podoba webu, samotná dokumentace obsahuje nyní pouze základní odkazy na stažení jednotlivých verzí, API dokumentace a odkazy na některá rozšíření. Postupně chci doplnit informace o entitách (základy, možnosti a přehled anotací, …), repozitářích, rady a postupy, co tu kdo publikoval, apod.
Pokud by měl někdo zájem zapojit se, budu rád, kompletní obsah je na GitHubu. Samotný web pak zde.
před 5 lety
- Tharos
- Člen | 1042
@duke: Stále nosím v hlavě ten problém
týkající se datumu 0000-00-00
. Implicitní passThru
by to řešit a vážně nad ním popřemýšlím, ale na co bys vůbec takový
datum převáděl? Na 30. 11. –0001? Není to trochu „ujeté“?
V dokumentaci k MySQL píšou, mimo jiné, následující:
“Zero” date or time values used through Connector/ODBC are converted automatically to NULL because ODBC cannot handle such values.
A tak přemýšlím, jestli by nebylo nejlepší takové nesmyslné datum převádět na NULL (rovnou je vnímat jako NULL)…
před 5 lety
- tomas.lang
- Člen | 54
@Tharos: ja bych se za automaticke konvertovani na NULL urcite primlouval, ale jen za prepokladu ze bude v property uvedeno DateTime|null; jinak by to asi opravdu chtelo prevest na neco stylu 30. 11. –0001…
před 5 lety
- majkl324
- Člen | 13
Před nějakou dobou jsem začal používat LeanMapper a nemůžu si ho vynachválit. Řeším ale jeden problém, který nejsem schopný nějak doladit.
Mám entitu Product a další entitu a tabulku s obrázky, které jsou ke každému produktu přiřazeny. Pokud chci získat všechny obrázky, vše funguje jak má:
<?php
/**
* @property-read int $id
* @property User $author m:hasOne(user_id)
* ...
* @property-read ProductImage $representImage
* ....
* @property-read ProductImage[]|null $images m:belongsToMany
*/
class Product extends BaseEntity
{
}
?>
Problém ale mám, pokud chci získat jenom jeden „reprezentační“ obrázek, respektive obrázek jako náhled v nějakém menu. Napadlo mě připsat vnořený SELECT do repository, ale řekl bych, že jsou určitě efektivnější způsoby jak k danému SQL přidat vnořený SELECT, který by z tabulky s obrázky vybral pouze jeden a použil se jen v případě, kdy bych representImage volal, ovšem nevím si s tím moc rady, i když si říkám, že řešení musí být jednoduché.
Díky za radu :)
před 5 lety
- castamir
- Člen | 631
@majkl324 mohl bys prosím popsat schéma a co by
měl vracet ten representImage
?
před 5 lety
- majkl324
- Člen | 13
Omlouvám se, tabulky jsou 2
- Product (id, author_id, title…)
- Product_Image (id, product_id, filename, upload_date)
Jeden product má více obrázků a representImage by měl vracet právě jeden obrázek (filename), byť jich je několik (měl by sloužit jako náhled), teoreticky je i jedno který.
To SQL, co jsem zkoušel napsat v repositáři by mohlo vypadat nějak takto
<?php
$row = $this->connection->select('*')
->select(
$this->connection->select('[product_image.file_name]')->from('[product_image]')
->where('[product_image.product_id] = ' . '[' . $this->getTable() . '.id]')
->orderBy('[' . $this->getTable() . '.id]')
->limit(1)
)->as('representImage')
->from($this->getTable())
->where('id = %i', $id)
->fetch();
?>
Z toho je už snad i můj záměr patrný a takto to funguje, ale zdá se mi to hrozně špatně řešené.. Nejsem si ani jistý, jestli je návrh těch tabulek správný, vše se to snažím učit takto za chodu, díky za trpělivost.
Editoval majkl324 (9. 3. 2014 16:53)
před 5 lety
- castamir
- Člen | 631
<?php
/**
* @property-read int $id
* @property User $author m:hasOne(user_id)
* ...
* @property-read ProductImage $representImage
* ....
* @property-read ProductImage[] $images m:belongsToMany
*/
class Product extends BaseEntity
{
public function getRepresentImage() {
if (reset($this->images) !== FALSE) {
$firstImage = current($this->images);
return $firstImage;
}
return NULL;
}
}
?>
pár poznámek:
- property $images nemusí být nutně read-only
- u vazeb m:belongsToMany nemusíš mít alternativní typ NULL – vrací to pole a to pole bude prázdné, pokud žádný vázaný záznam neexistuje… NULL je proto zbytečný
- pokud máš getter, tak se prioritně použije pro získání hodnoty
Editoval castamir (9. 3. 2014 17:34)
před 5 lety
- Tharos
- Člen | 1042
@majkl324: Ještě castamira doplním. Pokud bys nechtěl načítat z úložiště při přístupu k tomu jednomu reprezentativnímu obrázku všechny ostatní, můžeš použít následující „strategii“:
/**
* ...
* @property ProductImage[] $images m:belongsToMany
* @property-read ProductImage|null $representImage m:belongsToOne(#union)
*/
class Product extends BaseEntity
{
public function getRepresentImage()
{
return $this->getValueByPropertyWithRelationship('representImage', new Filtering(function (Fluent $statement) {
$statement->orderBy('rating')->desc()->limit(1);
}));
}
}
Takhle docílíš přesně toho, co potřebuješ, a jako bonus Lean Mapper vygeneruje hezké dotazy. V tom anonymním filtru jsem naznačil, že si můžeš za reprezentativní obrázek snadno vybrat třeba takový, který má nejlepší rating atp.
Edit: Ještě jsem kód opravil. :) Teď už by to mělo být správně…
Editoval Tharos (9. 3. 2014 20:15)
před 5 lety
- Pavel Macháň
- Člen | 285
@Tharos: Jak nejlip elegantne docilit tohoto?:
Máme 2 tabulky: product a product_price kde
produkt ma vice zaznamu v product_price (z duvodu historie cen kvuli fakturam
atd) a chci pokud vypisuju cenu produktu $product->actualPrice
(@property-read) dostat poslední záznam (nejnovejsi) z té
historie cen.
Editoval EIFEL (9. 3. 2014 20:45)
před 5 lety
- Tharos
- Člen | 1042
@EIFEL: Je to dokonalá analogie výše uvedené záležitosti. :)
Nejsnáze (na počet řádků) to lze zhruba takto:
/**
* ...
* @property-read ProductPrice|null $actualPrice m:belongsToOne(#union)
*/
class Product extends BaseEntity
{
public function getActualPrice()
{
return $this->getValueByPropertyWithRelationship('actualPrice', new Filtering(function (Fluent $statement) {
$statement->orderBy('date')->desc()->limit(1);
}));
}
}
Píšu to úplně z hlavy, ale mělo by to fungovat. Kdyžtak mi to reklamuj. :)
před 5 lety
- Tharos
- Člen | 1042
tomas.lang napsal(a):
@Tharos: ja bych se za automaticke konvertovani na NULL urcite primlouval, ale jen za prepokladu ze bude v property uvedeno DateTime|null; jinak by to asi opravdu chtelo prevest na neco stylu 30. 11. –0001…
Moje představa byla právě taková, že by se u nullable položky
databázová hodnota se samými nulami převedla na null
, zatímco
u ne-nullable položka by to celé skončilo výjimkou.
Převádění nevalidního data (a i dokumentace k MySQL to otevřeně přiznává, mimo jiné tím, že takové datum pak nelze použít ve funkcích) na cokoliv jakoby validního (30. 11. –0001) se mi trochu příčí…
Rád se nechám přesvědčit výhody/nevýhody toho či onoho řešení. Výhody výše uvedeného řešení vidím v tom, že je tahle anomálie MySQL „podchycena“, ale zároveň se pak v aplikaci nepracuje s datem, který nemá moc smysl.
před 5 lety
- Tharos
- Člen | 1042
janpecha napsal(a):
Ahoj, protože už mě fakt nebaví prohrabávat toto vlákno, tak jsem si dneska začal psát takovou vlastní „dokumentaci“ k LeanMapperu. Prozatím je to stále ve stádiu tvorby, hotová je základní podoba webu, samotná dokumentace obsahuje nyní pouze základní odkazy na stažení jednotlivých verzí, API dokumentace a odkazy na některá rozšíření. Postupně chci doplnit informace o entitách (základy, možnosti a přehled anotací, …), repozitářích, rady a postupy, co tu kdo publikoval, apod.
Pokud by měl někdo zájem zapojit se, budu rád, kompletní obsah je na GitHubu. Samotný web pak zde.
Je skvělé, že máš vůli pomoct s dokumentací!
Popravdě jsi mě svým přispěním trochu nakopl, protože by nebylo optimální, kdyby se nám dokumentace příliš roztříštila. Chápu, že svou pomalostí tomu dost nahrávám, ale právě jsi mě trochu popohnal. :)
Přes víkend jsem „hodil na papír“ (GitHub) to, jakou by dokumentace mohla mít optimálně strukturu, a podle toho jsem předpřipravil Wiki na GitHubu. Jsem pro použít GitHubovou Wiki, minimálně pro sepsání první verze kompletní dokumentace.
Zítra budu trávit část dne ve vlaku, a tak se zavazuji, že doplním obsah této stránky a pokusím se třeba i nějak více „vykopnout míč“.
před 5 lety
- Pavel Macháň
- Člen | 285
Tharos napsal(a):
@EIFEL: Je to dokonalá analogie výše uvedené záležitosti. :)
Nejsnáze (na počet řádků) to lze zhruba takto:
/** * ... * @property-read ProductPrice|null $actualPrice m:belongsToOne(#union) */ class Product extends BaseEntity { public function getActualPrice() { return $this->getValueByPropertyWithRelationship('actualPrice', new Filtering(function (Fluent $statement) { $statement->orderBy('date')->desc()->limit(1); })); } }
Píšu to úplně z hlavy, ale mělo by to fungovat. Kdyžtak mi to reklamuj. :)
Otestuju a dám vědět :)
BTW nevíš kdy asi vyjde nová verze ? :) Klidně setinková ;-) Potřeboval sem zrovna hasFilter a nemůžu nějak dokopat composer aby mě loadnul dev-develop (leanmaper pouzivam v baliku s modelem a ten az includuju composerem do projektu). Povedlo se me to az pomoci „require-dev“ jak u projektu tak v modelu.
Editoval EIFEL (9. 3. 2014 21:52)
před 5 lety
- Tharos
- Člen | 1042
@EIFEL: Jakmile dokončím tu „infrastrukturu“ kolem Wiki, tak novou stable verzi vydám. Takže nejspíš někdy v průběhu tohoto týdne.
před 5 lety
- Pavel Macháň
- Člen | 285
Tharos napsal(a):
@EIFEL: Jakmile dokončím tu „infrastrukturu“ kolem Wiki, tak novou stable verzi vydám. Takže nejspíš někdy v průběhu tohoto týdne.
Super :)
Tak sem zkoušel to stím actualPrice a nechápu jednu věc. Pokud vyberu 1 produkt tak je to OK. Pokud jich vyberu víc (findAll) a dám vypsat ceny tak to chcípne z nepochopitelného důvodu.
Mám 2 produkty:
foreach($this->productFacade->getAll() as $a){
dump(get_class($a->getActualPrice()));
}
- záznam: „Model\Entity\ProductPrice“
- záznam: „FrontModule\ProductPresenter“
Jak se tam proboha dostane presenter?
Pokud kouku na classu jen $a tak je to dobře Product
Editoval EIFEL (9. 3. 2014 23:50)
před 5 lety
- Tharos
- Člen | 1042
@EIFEL: Dokázal bys mi to na nějakém minimálním příkladě předvést? Zní to jako docela haluz. :) Nenapadá mě, jak by se tam nějaký presenter mohl dostat…
před 5 lety
- Pavel Macháň
- Člen | 285
Tharos napsal(a):
@EIFEL: Dokázal bys mi to na nějakém minimálním příkladě předvést? Zní to jako docela haluz. :) Nenapadá mě, jak by se tam nějaký presenter mohl dostat…
Edit: tak už je to jasný … OMG … tak sem jen blb …
Dobře to vrací NULL když to nenajde ten druhý záznam… Původně sem si nevšim, že tam ten záznam nebyl a zmátlo mě že to nemělo tu metodu (asi sem si nevsim, že je to null exception) tak sem se pomocí get_class kouknul co sem vlastně dostal… no a záhada je na svete
dump(get_class(null)); // = get_class() ... takže třída tam kde se to volá = presenter
Editoval EIFEL (10. 3. 2014 11:58)
před 5 lety
- elden46
- Člen | 37
Zdravim,
potreboval bych natuknout smer, jak resit nasledujici:
Mam 3 entity: dilo, verze, zaznam
Dilo je zakladni, z nej vazba hasmany do verze, z nej vazba hasmany do
zaznam.
Priklad: Dilo je „Pan Prstenu“ (autor, datum vydani), verze je „kniha/film/komiks“ (nakladatelstvi, id. cislo), zaznam je „ABC“ (ev. cislo, fyzicke umisteni).
Vytvarim vyhledavaci formular, do ktereho si uzivatel muze zadat vyhledavaci
parametry ze vsech tri entit a dostane seznam „zaznamu“ vyfiltrovanych podle
zadaneho nastaveni formulare. Jak na to, abych co nejefektivneji vyuzil LM a DB?
Udelat si filtrovani nad „Dilo“ a pote si pres foreach na „verzi“ a
nasledne foreach na „zaznam“ upravovat vyslednou kolekci (unsetovat
„dilo“) a pak vypisovat ze zbytku? Jak pak zajistit treba sortovani podle
sloupcu ze „zaznam“?
Nebo si napsat dotaz na urovni dibi a prijit tak o vyhody orm?
Editoval elden46 (10. 3. 2014 13:13)
před 5 lety
- duke
- Člen | 637
Tharos napsal:
tomas.lang napsal:
@Tharos: ja bych se za automaticke konvertovani na NULL urcite primlouval, ale jen za prepokladu ze bude v property uvedeno DateTime|null; jinak by to asi opravdu chtelo prevest na neco stylu 30. 11. –0001…
Moje představa byla právě taková, že by se u nullable položky databázová hodnota se samými nulami převedla na
null
, zatímco u ne-nullable položka by to celé skončilo výjimkou.
V podstatě souhlasím, ale doporučuji na to vyčlenit metodu, kterou by šlo přetížit (něco jako handleZeroDateTime). Ve výchozí implementaci by fungovala tak, jak navrhuješ.
před 5 lety
- majkl324
- Člen | 13
castamir, Tharos, díky moc za radu, vše funguje :)
před 5 lety
- tomas.lang
- Člen | 54
@Tharos: co se týče toho zpracování „špatných“ datetime, máš asi pravdu že v případně nevalidního vstupu (bez zadaného null) by bylo lepší vyhodit nějakou jasnou vyjímku, alespoň si toho vyvojář i lépe všimne :-)
@duke: +1 (jen název bych možná volil jiný?)
Každopádně z jiného soudku – chtěl jsem se zeptat jak to máte s testováním LM entit? Totiž pro unit testy bych nerad dělal připojení k DB (kdyby nic tak z pohledu rychlosti provádění testů), ovšem díky závislosti entit na DB a nemožnosti s nimi pracovat v detached stavu (hlavně tedy s entitami s 1:N a M:N vazbami) moc jiných možností nevidím. Přitom alespoň většiná mých entit má vcelku jednoduchou doménovou logiku a rád bych je testoval, a vysouvání této logiky do externích testovatelných tříd zbytečně povede jen k „hloupým“ entitám, což je jistě škoda. Přemýšlel jsem nad možností vlastního driveru v Dibi, který by testoval správně kladené SQL dotazy a vracel odpovídající data, ale bojím se že touto cestou bych se brzy dostal do nepěkných míst… Máte tedy prosím případně někdo řešení či alespoň nápad kudy na obra? :-)
Editoval tomas.lang (10. 3. 2014 22:01)
před 5 lety
- Tharos
- Člen | 1042
@tomas.lang: Co se testování týče, nemusí se na toho obra až tak složitě. :) Není zapotřebí mockovat přímo dibi driver.
Všimni si, že entity na nízké úrovni pracují pouze s Row
.
Connection
je v něm velmi důsledně zapouzdřené. A proto
stačí vytvořit mock (stub) pouze pro Row
.
Zde je malá ochutnávka:
/**
* @property int $id
* @property string $name
* @property Book[] $books m:belongsToMany
*/
class Author extends Entity
{
}
/**
* @property int $id
* @property string $name m:passThru(emphase)
*/
class Book extends Entity
{
protected function emphase($value)
{
return strtoupper($value);
}
}
class RowMock extends Row
{
private $mapper;
private $data;
public function __construct(IMapper $mapper, array $data = array())
{
$this->mapper = $mapper;
$this->data = $data;
}
public function isDetached()
{
return false;
}
public function getMapper()
{
return $this->mapper;
}
public function setConnection(Connection $connection)
{
}
public function hasConnection()
{
return true;
}
public function __set($name, $value)
{
$this->data[$name] = $value;
}
public function __get($name)
{
return $this->data[$name];
}
public function referencing($table, $viaColumn = null, Filtering $filtering = null, $strategy = null)
{
if ($table === 'book') {
$rows = [];
$data = [
['id' => 1, 'name' => 'First book'],
['id' => 2, 'name' => 'Second book'],
];
foreach ($data as $entry) {
$rows[] = new RowMock($this->mapper, $entry);
}
return $rows;
}
}
}
////////////////////
////////////////////
$connection = new Connection([ // fake!
'lazy' => true,
]);
$author = new Author(new RowMock($mapper));
$author->makeAlive($entityFactory, $connection, $mapper);
$author->name = 'John Doe';
echo $author->name, "\n";
foreach ($author->books as $book) {
echo "- $book->name\n";
}
Ukázka vypíše následující:
John Doe
- FIRST BOOK
- SECOND BOOK
Je to takhle pro Tebe použitelné? Anebo by sis to představoval ještě nějak lepší?
Editoval Tharos (11. 3. 2014 0:14)
před 5 lety
- duke
- Člen | 637
Narazil jsem na problém při persistování entity, kde používám passThru.
Mám následující entitu:
/**
* @property int $id
* @property Person|NULL $person m:hasOne
* @property string $username
* @property string $password
* @property array $roles m:passThru(decodeRoles|encodeRoles)
* @property bool $active
* @property \DateTime $created
*/
class User extends \LeanMapper\Entity
{
/**
* @param string
* @return string[]
*/
public function decodeRoles($roles)
{
return explode(',', $roles);
}
/**
* @param string[]
* @return string
*/
public function encodeRoles(array $roles)
{
sort($roles);
return implode(',', $roles);
}
Potom při následujícím kódu:
$user = new Entity\User;
$user->assign(array(
'username' => 'admin',
'password' => Passwords::hash('test'),
'roles' => array('admin'),
'person' => NULL
));
$userRepository->persist($user);
… dostávám výjimku se zprávou:
Error has occured (SQLSTATE[42S22]: Unknown column ‚admin‘ in ‚field
list‘)1054
přičemž vygenerované SQL query bylo dle logovacího panelu:
INSERT INTO `user` (`person_id`, `username`, `password`, `roles`)
VALUES (NULL, 'admin', '$2y$10$aamqetHX3YCg4COzR/u4WeIhTQBfce9Ilv/5JKvKKtw7yVYH3RAvO', admin)
Když však změním řadek:
* @property array $roles m:passThru(decodeRoles|encodeRoles)
za:
* @property string[] $roles m:passThru(decodeRoles|encodeRoles)
… dostávám výjimku LeanMapper\Exception\InvalidValueException se
zprávou:
Unexpected value type given in property ‚roles‘ in entity
Model\Entity\User, array of string expected, string given.
A konečně, když použiji řádek:
* @property string $roles m:passThru(decodeRoles|encodeRoles)
… kód proběhne bez chyb a uživatel se persistuje. Avšak nyní při
přístupu k $user->roles dostávám notice:
Array to string conversion (File:
…/vendor/tharos/leanmapper/LeanMapper/Entity.php:171)
Jak to má tedy být? Resp. co dělám špatně?
Prostě jen chci do databáze ukládat role jako řetězec a v entitách
s nimi pracovat jako s polem…
před 5 lety
- Šaman
- Člen | 2275
Střelba od boku – zkoušel jsi typ array|string?
před 5 lety
- Tharos
- Člen | 1042
@duke: Tohle mi zavání nějakým bugem, zvláštní
je ten úplně první SQL dotaz, který píšeš (s admin
bez
uvozovek). Jak budu mít chvilku, ověřím to (a vyřeším, pokud to
bude bug).
před 5 lety
- duke
- Člen | 637
@Šaman Ne, to opravdu nefunguje. Takovéto míchání typů v anotaci LeanMapper vůbec nepodporuje.
Zatím jsem to vyřešil tak, že jsem tam nechal typ string[]
a
zakomentoval tu kontrolu v Entity.php, která při __set
vyhazuje
výjimku, neboť zjevně se tam nebere v potaz to, že passThru setter může
změnit hodnotu z deklarovaného pole na skalár.
před 5 lety
- Tharos
- Člen | 1042
@duke: Skutečně to byla chyba. Typ přiřazované
hodnoty se kontroloval na nízké úrovni i při použití
passThru
, což je samozřejmě nežádoucí.
Mohl bys prosím ověřit verzi dev-hotfix/passThru
? Kdybys
nejel přes Composer, pushnul jsem tu větev i na GitHub…
Díky za perfektní report!
Editoval Tharos (13. 3. 2014 0:11)
před 5 lety
- Tharos
- Člen | 1042
Ahoj přátelé,
tak dokumentační Wiki je plně připravená.
Kdo tedy máte chuť přiložit ruku k dílu, vítejte na palubě. :) Sám se pustím do migrace obsahů, které mám rozpracované v tomto repositáři a také u sebe na disku.
Případní přispěvovatelé, určitě nepřehlédněte stránku o tom, jak přispívat.
Díky za pozornost a spolupráci!
před 5 lety
- janpecha
- Člen | 58
@Tharos: použít github wiki je dobrý nápad, hned jak budu mít trochu času, zkusím přispět.
před 5 lety
- duke
- Člen | 637
Tharos napsal:
@duke: Skutečně to byla chyba. Typ přiřazované hodnoty se kontroloval na nízké úrovni i při použití
passThru
, což je samozřejmě nežádoucí.Mohl bys prosím ověřit verzi
dev-hotfix/passThru
? Kdybys nejel přes Composer, pushnul jsem tu větev i na GitHub…
Tak jsem to otestoval a pokud zvolím anotaci:
* @property array $roles m:passThru(decodeRoles|encodeRoles)
… tak to, zdá se, funguje dobře.
Pokud zvolím typ string[]
nebo string
, chová se
to stejně jako před tím. Tj. pro typ string[]
to stále
kontroluje typ přiřazené hodnoty na nízké urovni i při použití passThru
a vyhodí výjimku.
Mám za to, že anotace s typem string[]
by měla fungovat…
před 5 lety
- David Ďurika
- Člen | 341
Tharos napsal(a):
Případní přispěvovatelé, určitě nepřehlédněte stránku o tom, jak přispívat.
ahoj ak ti nevadi ze by som to pisal po slovesnky, tak by som ti s tym rad pomohol… dokonca som uz aj zacal s IMapper-om
a dalsia vec, tie diskusne stranky k sa motnym strankam mi pridu trocha naprakticke… (vid moj koment https://github.com/…ivat-diskuze)
před 5 lety
- Tharos
- Člen | 1042
@duke: Aktuálně Lean Mapper zápisy typu
string[]
nepodporuje. []
lze použít pouze
u objektů.
Já osobně to u skalárních hodnot totiž považuji tak trochu za zbytné.
Hlavní výhodu zápisu Book[] $books
vidím v tom, že kdy pak
iteruji nad $books
, IDE mi pro každou knihu napovídá její
property. Z tohohle pohledu zápis string[]
nemá žádný
přínos oproti array
.
No a co se validace dat týče… Ona už teď není kdo ví jak důkladná. Mám dojem, že se kontroluje jenom první hodnota. Přínos je spíš takový, že hned zjistíš, když vytvoříš kolekci nějakých úplně špatných typů. Kontrolovat úplně všechny hodnoty se mi nechce z výkonnostního hlediska… U velkých kolekcí se každý průchod počítá.
Takže ten fix z mého pohledu funguje. U passThru
se
předpokládá, že type hint bude takový, jaká bude hodnota v PHP. V Tvém
případě tedy array
.
před 5 lety
- Tharos
- Člen | 1042
achtan napsal(a):
ahoj ak ti nevadi ze by som to pisal po slovesnky, tak by som ti s tym rad pomohol… dokonca som uz aj zacal s IMapper-om
Vůbec nevadí. :)
a dalsia vec, tie diskusne stranky k sa motnym strankam mi pridu trocha naprakticke… (vid moj koment https://github.com/…ivat-diskuze)
Budou to issues. :) Jak budu mít chvilku, Wiki upravím.
Editoval Tharos (14. 3. 2014 15:21)
před 5 lety
- duke
- Člen | 637
Tharos napsal:
@duke: Aktuálně Lean Mapper zápisy typu
string[]
nepodporuje.[]
lze použít pouze u objektů.Já osobně to u skalárních hodnot totiž považuji tak trochu za zbytné. Hlavní výhodu zápisu
Book[] $books
vidím v tom, že kdy pak iteruji nad$books
, IDE mi pro každou knihu napovídá její property. Z tohohle pohledu zápisstring[]
nemá žádný přínos oprotiarray
.
Rozumím tomu, že z hlediska napovídání IDE v tom nemusí být žádný přínos. Přesto si myslím, že by to LeanMapper mohl umět (to, že to lze použít jen u objektů a u jiných typů ne, je trochu WTF). A pokud to neumí, měl by alespoň vyhazovat výjimku už při zpracování takových anotací (případně s doporučením: use „array“ as type). Výjimka, kterou to vyhazuje teď, je zavádějící.
No a co se validace dat týče… Ona už teď není kdo ví jak důkladná. Mám dojem, že se kontroluje jenom první hodnota. Přínos je spíš takový, že hned zjistíš, když vytvoříš kolekci nějakých úplně špatných typů. Kontrolovat úplně všechny hodnoty se mi nechce z výkonnostního hlediska… U velkých kolekcí se každý průchod počítá.
Jedna věc je kvantita (validace celé kolekce vs jen prvního prvku; napadá mě také možnost líné validace pokud by se pracovalo s nějakým iterátorem, či volitelná validace, kterou by šlo např. aktivovat jen ve vývojovém režimu, atp.) a druhá věc je kvalita (validují se všechny typy polí vs validují se jen pole objektů; zde nevidím důvod omezovat se jen na pole objektů).
Takže ten fix z mého pohledu funguje. U
passThru
se předpokládá, že type hint bude takový, jaká bude hodnota v PHP. V Tvém případě tedyarray
.
Pro anotaci array
už opravdu funguje a za tuto rychlou opravu
děkuji.
před 5 lety
- Šaman
- Člen | 2275
U toho string[]
by asi lepší hláška pomohla, ale podpora
tohoto zápisu imho nemá v php význam. Jinak teď dělám v Doctrine a na
základní práci mi přijde LM dokonce jednodušší (v LM stačí přidat
anotaci, v Doctrině property a setter/getter). Jediné, co tomu chybí a čím
Doctrine trumfuje je aktualizace databáze podle aktuáního kódu (čímž
odpadá nutnost vytvářet sql patche a řešit který má být dřív… při
práci více vývojářů na jednom projektu to je k nezaplacení).
před 5 lety
- castamir
- Člen | 631
@Šaman to už se tu někde řešilo… DBAL z docrine se dá použít i v LM…
Nedávno jsem narazil na jeden blogpost o přechodu z NDBT na Doctrine a docela jsem se zhrozil z podoby entity. Krom tvých nedostatků bych přidal ještě nutnost duplikovat datový typ v anotaci…
před 5 lety
- Tharos
- Člen | 1042
elden46 napsal(a):
Zdravim,
potreboval bych natuknout smer, jak resit nasledujici:
Mam 3 entity: dilo, verze, zaznam
Dilo je zakladni, z nej vazba hasmany do verze, z nej vazba hasmany do zaznam.Priklad: Dilo je „Pan Prstenu“ (autor, datum vydani), verze je „kniha/film/komiks“ (nakladatelstvi, id. cislo), zaznam je „ABC“ (ev. cislo, fyzicke umisteni).
Vytvarim vyhledavaci formular, do ktereho si uzivatel muze zadat vyhledavaci parametry ze vsech tri entit a dostane seznam „zaznamu“ vyfiltrovanych podle zadaneho nastaveni formulare. Jak na to, abych co nejefektivneji vyuzil LM a DB? Udelat si filtrovani nad „Dilo“ a pote si pres foreach na „verzi“ a nasledne foreach na „zaznam“ upravovat vyslednou kolekci (unsetovat „dilo“) a pak vypisovat ze zbytku? Jak pak zajistit treba sortovani podle sloupcu ze „zaznam“?
Nebo si napsat dotaz na urovni dibi a prijit tak o vyhody orm?
Odpovídám pozdě, asi už budeš mít tuhle věc vyřešenou…
Napsáním vlastního dotazu na úrovni dibi nemusíš přijít o výhody
ORM. Napsal bych si na to buďto metodu v repositáři, anebo nějaký Query
Object. Stačí provést SELECT potřebných dat a v restrikci při-joinovat
hodnoty ze zbylých tabulek, podle kterých se má výsledek omezovat. A pak to
jen celé obalit voláním ->createEntites(...)
v repositáři.
Výše uvedeným způsobem snadno libovolně omezíš záznamy v rámci načítání „hlavních entit“, a to i na základě dat z jiných tabulek. Pokud bys dále potřeboval omezit data při traverzování, můžeš si nadefinovat potřebné filtry. Ty mohou jako parametr přijímat například stejný Query Object, jaký byl použit pro získání dat z hlavní tabulky.
Je to takhle „zhutněle“ vysvětlené srozumitelné? :) Pokud ne a zajímalo by Tě to víc, klidně se mi ozvi na Skype (v.kohout).
před 5 lety
- Šaman
- Člen | 2275
Díky, tou dobou jsem ještě netušil, že se pustím do většího projektu na Doctrině a tyhle příspěvky jsem přeskakoval. :)
před 5 lety
- Tharos
- Člen | 1042
Ahoj,
mile rád bych odlehčil tomuhle dloouhému vláknu a napadlo mě, že bychom mohli významnou část diskuze dále vést na GitHubu v issues.
Issues, jak asi nikoho nepřekvapí, nejsou jenom o chybách. Vytvořil jsem následující sadu štítků:
- Approwed feature
- Bug
- Duplicate
- Question
- RFC
- Wiki
Když je budeme používat, tak by mělo být možné na GitHubu řešit vše mnohem přehledněji – od dotazů přes RFCčka až po bugy.
Vím, že j zapojení se je zapotřebí mít účet na GitHubu, ale to je myslím malicherná vstupní bariéra.
Díky za pozornost. :)
Editoval Tharos (16. 3. 2014 21:56)
před 5 lety
- Pavel Macháň
- Člen | 285
Možná(asi určitě) se to tu už řešilo ale najít to v 1k postech je to
dost šílený najít. Jak by jste řešili následující:
https://www.dropbox.com/…pi/LM-02.png
- Foo > id: 1, parent: null
|- FooFoo > id: 2, parent: 1
|- FooTwo > id: 3, parent: 1
|- FooTwoOne > id: 4, parent: 3
- Bar > id: 5, parent: null
|- BarBar > id: 6, parent: 5
Položky:
One > kategorie: 1
Two > kategorie: 4
Three > kategorie: 3
Four > kategorie: 2
Five > kategorie: 4
A našim cílem je pro každou kategorii vypsat své vlastní položky + ty které vlastní i jeji potomci.
Výsledná data:
Foo > id: 1 => One, Two, Three, Four, Five
FooFoo > id: 2 => Four
FooTwo > id: 3 => Two, Three, Five
Editoval EIFEL (17. 3. 2014 18:03)
před 5 lety
- castamir
- Člen | 631
@EIFEL jedním z mnoha způsobů (vím o 4), jak to řešit, je použití closure tables. Můj blog, kde popisuju jejich použití, je sice teď vypnutý, ale alespoň odkážu na podobný článek: http://blog.voracek.net/…rochu-jinak/
Předem však upozorňuji na drobné nedostatky v uvedených sql – ověř si, zda doopravdy dělají to, co chceš.
před 5 lety
- Pavel Macháň
- Člen | 285
castamir napsal(a):
@EIFEL jedním z mnoha způsobů (vím o 4), jak to řešit, je použití closure tables. Můj blog, kde popisuju jejich použití, je sice teď vypnutý, ale alespoň odkážu na podobný článek: http://blog.voracek.net/…rochu-jinak/
Předem však upozorňuji na drobné nedostatky v uvedených sql – ověř si, zda doopravdy dělají to, co chceš.
@castamir Díky mrknu na to :) Closure table sem neznal.
před 5 lety
- greeny
- Člen | 406
Ahoj, mám menší dotaz:
Pokud mám anotaci m:belongsToMany
, dá se nějak upravit
pořadí, v jakém se vrátí ty entity? Dá se to nějak udělat na úrovni
SQL nebo musím pomocí m:passThru
prohodit to pole nějakým
usortem?
Editoval greeny (25. 3. 2014 9:54)
před 5 lety
- Tharos
- Člen | 1042
@greeny: Dá úplně snadno, stačí použít filtr,
který do toho dotazu doplní potřebný ORDER BY
.
Jinak koukám, že máš účet na GitHub – kdybys cokoliv potřeboval,
ptej se prosím přednostně v Lean Mapper issue.
Stačí vytvořit issue a dát ji štítek question
. Díky!
před 5 lety
- greeny
- Člen | 406
@Tharos – jo, já si totiž moc nečetl ty posty nad tím, všiml jsem si toho až po odeslání dotazu ;) Díky
Editoval greeny (25. 3. 2014 11:41)
před 5 lety
- johnson
- Člen | 1
Ahoj, prosím o radu. Chtěl bych nějak řešit unikátnost záznamů při persistenci. Příkládám příklad, na kterém se to pokusím vysvětlit. Entity a repositáře vychází z quickstartu k leanmapperu.
<?php
$tag = new Tag();
$tag->name = "Horror";
$tagRepository->persist($tag);
$book = new Book();
//zde by bylo přiřazení povinných hodnot
$book->addToTags($tag);
$bookRepository->persist($book);
?>
V TagRepository bych chtěl přetížit metodu persist a v ní zkontrolovat
zda tag se zadaným name již existuje. Pokud ano, tak nezakládat nový a
předanou entitu tagu označit jako existující a přiřadit ji id záznamu
v db. Čili potom při volání $book->addToTags($tag)
bude
kniha propojena s již existujícím tagem. Doufám, že jsem to popsal
srozumitelně.
Poradíte jak na to prosím? Co by mělo být obsahem přetížené metody persist a zda to vůbec takto řešit?
Editoval johnson (31. 3. 2014 13:06)
před 5 lety
- Tharos
- Člen | 1042
@johnson: Mělo by to jít velmi jednoduše.
V repositáři se stačí někde před vytvořením entity podívat do
databáze, jestli už taková entita existuje, a pokud ano, můžeš tu do
repositáře předanou na tu existující „napojit“ pomocí metody Entity::attach
.
Asi bych pak ještě zkontroloval, jestli v té předané nebyly pozměněny nějaké hodnoty, které bych kdyžtak v úložišti také aktualizoval…
Anebo by mělo jít použít v repositáři konstrukci
INSERT ... ON DUPLICATE KEY UPDATE
. To by bylo asi ještě lepší,
čistější řešení. :)
Stačí Ti takhle rámcové navedení? Pokud ne, můžeme to probrat ještě na GitHubu v issues. Díky!
před 5 lety
- plzurq
- Člen | 3
Ahoj,
jde nějak elegantně vyřešit následující?
Již mám article, který má nějaké tagy (např 1,2,3). Updatuju ho a ukládám a tagy upravím (a vyberu 2,3,4)
Chtěl bych, aby se mi při ukládání smazala 1 a přidala 4.
$tags=[2,3,4];
$article = //vytahnu z DB article
$article->addToTags($tags);
$this->repo->persist($article);
Editoval plzurq (7. 4. 2014 21:40)