Nextras Orm defalutni filtrovani

tomasde
Člen | 26
+
0
-

Mam otazku jak nastavit defaultni filtrovani kdyz mam treba vypis takto

entity1 = $orm->entita1->findBy([
    ICollection::OR,
    ['time' => null],
    ['time>=' => $now],
])->orderBy('time', ICollection::ASC_NULLS_LAST);

foreach($entity1 as $entita1){
	foreach($entita1->movie->events as $event){
	dump ($event->time);
	}
}

Vytvori se Mysql dotaz

SELECT `events`.* FROM `events` AS `events` WHERE `events`.`movie_id` IN ('1', '2');

Jenze ja potrebuju aby se ty eventy filtrovali jeste podle time >= NOW()

SELECT `events`.* FROM `events` AS `events` WHERE `events`.`movie_id` IN ('1', '2') AND  `events`.`time` >=NOW();

Pokazde kdyz budu chtit vytahnout eventy tak je chci mit vzdy vetsi nez je aktualni cas.

Nejde nekde zadat callback nebo naka metoda ?

Zkousel jsem to udelal tak, ze v Movie budu mit metodu getEvents(); a v ni

   public function getEvents(): ICollection {
        return $this->events->toCollection()->findBy(['time>=' => new \DateTime()]);;
    }

jenze ja si potrebuju prvne zjistit jestli ten movie hasEvents();

  public function hasEvents():bool{
        return count($this->events) > 0;
    } // tady se mi zavola sql prikaz bez toho filtrovani time
 // Tohle nefunguje to se vytvori dokonce 3x sql dotazy na events
  public function hasEvents():bool{
		$this->getEvents();
        return count($this->events) > 0;
    }

Zkousel jsem i pretizit v repository metody jako findByIds nebo findBy tyhle metody nejsou vubec volany

Editoval tomasde (26. 1. 13:33)

stepos2
Člen | 54
+
0
-
public function getEvents(): ICollection
{
	return $this->events->toCollection()->findBy(['time>=' => new \DateTime()]);
}

public function hasEvents(): bool
{
	return $this->getEvents()->count() > 0; // nebo ->countStored(), který to počítá dotazem do DB
}
tomasde
Člen | 26
+
0
-

to jsem prave ze zkousel a udela se to, ze se mi vytvori tolikrat sql dotaz kolik mam vypis z prvni tabulky

SELECT `m_vorschau`.* FROM `m_vorschau` AS `m_vorschau` WHERE (`m_vorschau`.`time` IS NULL) OR (`m_vorschau`.`time` >= '2025-01-26 16:07:06.498593') ORDER BY `m_vorschau`.`time` IS NULL, `m_vorschau`.`time` ASC

SELECT `m_movies`.* FROM `m_movies` AS `m_movies` WHERE `m_movies`.`id` IN ('4f70abf3', '5f725b80', '0f1b0eed')

SELECT `m_events`.* FROM `m_events` AS `m_events` WHERE (`m_events`.`time` >= '2025-01-26 16:07:06.535753') AND (`m_events`.`movie_id` IN ('0f1b0eed', '4f70abf3', '5f725b80'))

SELECT `m_events`.* FROM `m_events` AS `m_events` WHERE (`m_events`.`time` >= '2025-01-26 16:07:06.552022') AND (`m_events`.`movie_id` IN ('0f1b0eed', '4f70abf3', '5f725b80'))

SELECT `m_events`.* FROM `m_events` AS `m_events` WHERE (`m_events`.`time` >= '2025-01-26 16:07:06.553081') AND (`m_events`.`movie_id` IN ('0f1b0eed', '4f70abf3', '5f725b80'))

To chce ten filter zadat nekam jeste predtim nez si ty events vyzadam, aby to pak vyjelo vsechno dohromady v jednom dotazu.
Aby trida OneToMany zavolalo nakou callback funkci pokud budu vyzadovat ty events.
Skoda ze to nevola EventsRepository, tam bych to v nake pretizene metode pridal.

Editoval tomasde (26. 1. 16:23)

hrach
Člen | 1844
+
+1
-

@tomasde to vypada, ze je problem v tom, ze kdykoliv se to getEvents() vola, mas v podmince jiny cas (now). Jednoduchy fix je vymazat tomu casu microsecond – a nebo si nekde ten time ulozis a posles do toho getEvets() jen tu jednu – vzdy stejnou instanci casu.

PS: vzhledem k tomu, jak ma php blby API na datetime, tak mozna ta druha verze je jednodussi.

tomasde
Člen | 26
+
0
-

neni lepsi tam napsat toto ?

 return $this->events->toCollection()->findBy(['time>=' => 'NOW()']);

Ale rve to ze to chce Datetime, ma dbal literal neco jako ma nette database ?

Mimochodem Ai je uplne k hounu vymejsli si neexistujici tridy a metody
Kdyz to nevi tak si to vymysli nakou kravinu, hlavne aby to neco napsalo.

Editoval tomasde (27. 1. 12:17)

m.brecher
Generous Backer | 905
+
0
-

@tomasde

Mimochodem Ai je uplne k hounu

Jaké AI používáš ? Já používám free Copilot dostupný v prohlížeči Edge a zadávám pečlivě formulované prompty v angličtině. Na dotazy z oblasti masových technologií (css, javascript, PHP, OOP, Git, phpStorm, composer) dostávám špičkové odpovědi, obvykle řádově lépe formulované než když pošlu dotaz na fórum. Mě přijde AI jako skvělý nástroj, denně posílám desítky promptů. To, že někdy odpoví nesmysl je v pořádku – algoritmy AI jsou inspirované strukturou lidského mozku (neuronová síť). Nelámej nad AI hůl on člověk musí používáním přijít na to, jak to efektivně použít.

hrach
Člen | 1844
+
0
-

@tomasde no, teoreticky by bylo, ale toto v Nextras ORM zaspat nejde. napr. proto, te v tom $events muzes mit nejaky nepersistovany relationship (tzn. co v db jeste neni) a bude to porad spravne fungovat.

Dostat datetime bez mirkosekund muzes takto: (chatgpt):

function getCurrentDateTime(): DateTime {
    return DateTime::createFromFormat('Y-m-d H:i:s', (new DateTime())->format('Y-m-d H:i:s'));
}
tomasde
Člen | 26
+
0
-

ja se ale ptal primo na sql dotaz NOW()
vsak je lepsi napsat NOW() nez vytvaret toto

 return DateTime::createFromFormat('Y-m-d H:i:s', (new DateTime())->format('Y-m-d H:i:s'));

Proto jsem psal ze ai je blba protoze jsem se ptal kde mohu zadat sql literal a ona si vymysli neexistujici tridy a metody.
Protoze je ocekavano datetime ale mela by byt i moznost pouzit NOW()

Marek Bartoš
Nette Blogger | 1309
+
0
-

mela by byt i moznost pouzit NOW()

No, neměla. ORM je abstrakce nad databází, snaží se tě od ní odstínit. Jen tak může fungovat beze změn v kódu nad různými databázemi i s jinými úložišti dat. Cokoli pro specifické úložiště patří do mapperu a collection functions.

V tvém případě se vytváří nové dotazy nejspíš kvůli tomu, že čas který předáváš se pokaždé liší. Možně řešení je vytvořit si jednu instanci DateTime a do všech findBy předávat tu, namísto toho abys pokaždé vytvářel novou.
Ideálně si však kolekci profiltrovanou skrze findBy vytvoř jen jednou a předávej si všude tu, namísto opakovaného volání findBy.

tomasde
Člen | 26
+
0
-

Dobre diky.
Jeste bych mel otazku, jak udelat
Nebo jak docilit toho, kdyz si vyjedu entity

 $entita = $this->orm->entityRepository->findByIds([array_keys($pole)])->fetchPairs('id');
    foreach ($pole as $id => $data) {
        if (!isset($entita[$id])){
           $entita[$id] = (new Entita)->id = $id;
       }
        $entita[$id]->prop1= $data->blabla;
        $entita[$id]->prop2= $data->bleble;
         $this->orm->persist($entita[$id]);
       }
       $this->orm->flush();

pokud proeperty budou stejny tak se neprovede nic.
Pokud nejaka hodnota bude jina provede se update.
A samozrejme pokud entita neni vytvori nova, se tudiz se provede Insert.

Jde mi o te ze kdyz parsuji Xml kde mam hodne dat a chci to pak ukladat do databaze abych mel co nejmin sql dotazu.

Editoval tomasde (2. 2. 22:53)

tomasde
Člen | 26
+
0
-

asi jsem na to prisel, pretizil jsem metodu v entite

public function setValue(string $name, $value): void{
        if(isset($this->$name) && $this->$name === $value) return;
        parent::setValue($name, $value);
}
Marek Bartoš
Nette Blogger | 1309
+
0
-

Takto jsem to kdysi řešil já

	public function __set(string $name, mixed $value): void
	{
		if (!$this->hasValue($name) || $this->getValue($name) !== $value) {
			$this->setValue($name, $value);
		}
	}