Ik maak een applicatie met een agenda functie.
De agenda is een soort grid waarin je de dagen van de maand ziet, zoals een typische kalender.

De afspraken tabel in MySQL:
agenda_id In de applicatie kan een gebruiker eventueel meerdere agenda's maken.
user_id Gebruiker die de afspraak heeft gemaakt.
title Korte tekst afspraak
descriptionRuimte voor langere tekst.
start_date Begindatum/tijd van afspraak
end_date Einddatum/tijd van afspraak
location Veld voor locatie/adres van afspraak.

Als ik een specifieke agenda wil weergeven, en het weergavebereik is bijvoorbeeld een maand, haal ik alle afspraken op uit de database die een begin- of einddatum hebben binnen het weergavebereik.
Ik krijg dan een resultset uit de database met de afspraken die in het huidige relevante "bereik" liggen dat ik nodig heb om de agenda te tonen aan de gebruiker.
Vervolgens maak ik een array van AgendaDay objecten (is een class), met het aantal elementen gelijk aan het aantal dagen in de weer te geven periode.
De AgendaDay class heeft op zijn beurt een array voor de afspraken die op die dag plaatsvinden.

Ik pak dus de afspraken uit de resultset van de database, en zet deze in de juiste AgendaDay objecten die corresponderen met de dag waarop de afspraak valt.

De data structuur bestaat dus uit een array van AgendaDay objecten, die op hun beurt de afspraken in zich hebben.

Nu heb ik meerdere bedenkingen:
- Het is mogelijk dat het beginmoment en eindmoment van een afspraak op verschillende dagen ligt. Ik zou dan bijvoorbeeld dezelfde afspraak in twee AgendaDay objecten kunnen zetten om dit te tonen in de browser.
- Het kan zelfs zo zijn dat een afspraak meerdere dagen duurt (zoals een vakantie). Dat zou betekenen dat nog veel meer AgendaDay objecten dezelfde afspraak kunnen bevatten om deze te kunnen tonen.
- Het kan zijn, dat een afspraak de grens tussen maanden overscreidt.

Ik vraag me dus af of dit wel de juiste aanpak is, en of het wel handig is.

Ook wil ik in de toekomst een functie implementeren waarmee de gebruiker een herhaalde afspraak kan toevoegen aan zijn agenda. Dus een afspraak die structureel elke week/maand in de agenda staat.

Het blijkt nog best ingewikkeld te zijn soms, als je er goed over nadenkt.
Heeft iemand ideeën of tips misschien?
Frank Nietbelangrijk op 24/02/2022 22:07:12
->andWhere('start BETWEEN :start AND :end OR end BETWEEN :start AND :end OR start < :start AND end >:end')

Deze moet je even toelichten...
Alle afspraken tussen die tussen :start en :end "spelen" (van belang zijn) =
- de afspraak begint (start) tussen :start en :end (maar loopt misschien daarna door)
- de afspraak eindigt (end) tussen :start en :end (maar begint misschien daarvoor)
- de afspraak begint (start) ervoor en eindigt erna (maar loopt dus _door_ de periode heen
Misschien denk ik te simpel.

Waarom moet alles toch, en dus ook een afspraak, überhaupt OO zijn?
Zo denken mensen gewoonlijk niet, het is maar een platte regel in een tabel?
Met een begintijd, een eindtijd en een naam.
Waarom je hiervoor aparte objecten programmeren?
PHP haalt zoiets als array uit je database en je kan daar zelfs
nog een standaard active record object voor gebruiken.

In de database sla je natuurlijk niet de begintijd op met een duur.
Dan moet je voor elke query, zoals voor overlap, eerst de eindtijd berekenen.
Als je in enkele gevallen de duur wilt weten kan je dat de database laten uitrekenen.

In de meeste gevallen is een query builder niet nodig, het is slechts een extra
complicatie over SQL, die niets toevoegt en de leesbaarheid bemoeilijkt.
Zo ook deze:
->andWhere('start BETWEEN :start AND :end OR end BETWEEN :start AND :end OR start < :start AND end >:end')

In de eerste plaats snap je niet wat er staat, en je moet toch nog zelf SQL invoegen.
Een query builder zou dan op z'n minst compleet moeten zijn en een voorziening moeten
hebben voor booleaanse logica. Anders moet je alsnog bewust zijn van het verschil tussen
ANSI SQL (of het gebrek daar aan) en de database-specifieke uitbreidingen.

Bijvoorbeeld: bij PostgreSQL hoef je niet eens zelf nadenken om de overlap tussen twee
perioden uit te rekenen. Je kan hiervoor de operator OVERLAPS gebruiken.
https://www.postgresql.org/docs/current/functions-datetime.html
Overigens is de OVERLAPS operator wel degelijk ANSI SQL (editie 2011),
maar zoals wel vaker wordt het niet door MySQL of zelfs MariaDB ondersteund.
Die 'databases' zijn dermate beperkt dat je zelfs voor zoiets simpels in je eigen tijd het wiel opnieuw moet uitvinden...

En als we dat doen, snap ik niet waarom de vier situaties worden zien als uitgangssituatie.
Want het is een resultaat van slechts twee vergelijkingen.
Neem de perioden p1 (van, tot) en p2 (van, tot), dan heb je genoeg aan:

WHERE p1.van < p2.tot 
  AND p2.van < p1.tot

(NB: merk op dat er is een verschil is tussen 'tot', en 'tot en met')
Ad we mogen allemaal zelf ons ding doen. Waarom alles in OOP "moet" kan ik wel iets over zeggen maar dat zou dit topic kapen. Deze query had natuurlijk zeker ook in plain SQL kunnen staan maar ook dat is slechts een keuze en mede afhankelijk van het pakket waarmee je werkt.

PostgreSQL heeft zeker bepaalde voordelen ten opzichte van MySQL maar een feit is dat MySQL nog steeds het meest wordt aangeboden door de verschillende providers en waarschijnlijk ook in het lesmateriaal.


WHERE p1.van < p2.tot 
  AND p2.van < p1.tot

Jouw query lijkt te werken. Eigenlijk was ik eerder deze week daar naar op zoek maar ik kon hem zo snel niet op tafel hoesten en kwam toen bovenstaande query tegen op stackoverflow. Ik ga hem in de eerdere post verwerken. Bedankt voor deze waardevolle aanvulling.

Tuurlijk mag iedereen z'n eigen ding doen.
Alleen zie ik geen meerwaarde van een hoop (OO-) code die je moet onderhouden,
terwijl je ook code kan schrijven die beter presteert en makkelijker te lezen/bewerken is (met de juiste syntaxkleuren):
<?php
$sql = <<<'EOQ'
SELECT *
FROM a
WHERE start < $1 AND end < $2
ORDER BY a.start ASC
EOQ;
$res = $db->query_params($sql, [$end, $start]);
?>

Maar smaken verschillen en iedereen die z'n tijd wil verbranden met MySQL houd ik niet tegen.

P.S.: SO link

Reageren