[PHP] OOP factuursysteem

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • vmsw
  • Registratie: Juli 2006
  • Laatst online: 24-02 19:47
Inmiddels ben ik al een aardige tijd (paar weken) aan het werken aan een factuursysteem, en deze probeer ik zo 'juist mogelijk' te maken. Dus gebruik van OOP en zo logisch mogelijke code. Echter loop ik nu vast omdat ik niet goed weet wat ik hiermee moet. Ook in mijn boeken (ook van Java) kan ik geen goed idee ervan krijgen.

Bijvoorbeeld:
Ik heb een object $order van klasse 'order' die onder andere de gegevens heeft van een 'relatie' (= klant), en diverse objecten van 'product'. Vervolgens kan ik bijvoorbeeld met de volgende acties gegevens krijgen:

PHP:
1
2
$order->relatie->volledige_naam; //bijv. "Pieter Vergiet"
$order->product(5)->prijs; //bijv. 500 cent (= 5 euro)


Objecten initialiseer ik door het ID door te geven. Een object bevat standaard dan ook alleen het ID. Zodra een gegeven uit dit object opgevraagd of gewijzigd wordt, worden alle gegevens uit de database (met behulp van mijn SQL connectie-klasse) opgehaald.
Voorbeelden van mijn objecten: relatie, order en product, maar ook bijv. naam, adres, telefoonnummer etc.

Maar, wat ik nu als probleem zie: stel, ik laat een lijst maken van alle orders en laat hier iedere keer het ordernummer melden. Dan gaat hij al die ordernummers opnoemen, maar dus ook heel veel objecten met gegevens 'invullen', zo ook heel veel losse SQL commando's sturen om alle gegevens op te vragen.
Dit leidt tot relatief veel geheugengebruik, en veel databaseconnecties.
Een ander (gelijk soort) voorbeeld is een optelling van de jaaromzet (dus combinatie van alle factuurbedragen). Dit leidt dan ook tot gigantisch veel SQL-commando's en geheugengebruik, omdat heel veel gegevens opgehaald gaan worden.

Wat wordt er van mij verwacht om dit zo logisch/juist mogelijk te doen? Gebruik ik de OOP juist?

[ Voor 3% gewijzigd door vmsw op 07-02-2010 14:11 ]


Acties:
  • 0 Henk 'm!

  • krvabo
  • Registratie: Januari 2003
  • Laatst online: 11-09 22:10

krvabo

MATERIALISE!

Je kunt je classes zo maken dat je ook objecten aan kunt maken zonder een ID op te geven. Maak daarnaast functies als setId(), setPrice(), setName(), etc of een functie (constructor?) waarmee je alle gegevens in één keer kunt opgeven.

In het deel waar je de lijst wilt maken kun je dan een query doen van meerdere rows, en met een for/foreach/while nieuwe objecten aanmaken zónder steeds de gegevens op te laten halen met een enkele query.
Let er wel op dat php geen function overloading kent zoals java dus het volgende werkt niet

PHP:
1
2
3
4
<?
public function __construct($iId) { }

public function __construct($iId, $sName, $dPrice) { }


Afgezien van een andere naam gebruiken kun je bijvoorbeeld wel zoiets doen:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?
public function __construct($iId, $sName = null, $dPrice = null) { 

  $this->iId = $iId;

  if ($sName == null && $dPrice == null) {
    
     $this->getById();

   } else {

      $this->sName = $sName;
      $this->dPrice = $dPrice;

   }
}

Of kijken naar het aantal parameters waarmee een functie is aangeroepen.

[ Voor 5% gewijzigd door krvabo op 07-02-2010 14:14 ]

Pong is probably the best designed shooter in the world.
It's the only one that is made so that if you camp, you die.


Acties:
  • 0 Henk 'm!

  • TheGrandWazoo
  • Registratie: Januari 2009
  • Laatst online: 20:24
Dit leidt tot relatief veel geheugengebruik, en veel databaseconnecties.
Ik mag hopen dat de database connectie 1 keer wordt opgebouwd en daarna door het hele script wordt gebruikt, totdat het script is afgelopen en weer uit het geheugen verwijderd wordt. De hoeveelheid objecten die je aanmaakt draagt wel bij aan het geheugen gebruik, maar dat zal toch niet dusdanig zijn dat je memory limiet wordt gehaald? Tot zover ik weet is het geheugengebruik verder geoptimaliseerd in PHP 5.3, itt tot 5.2 en lager. Zonder enige code te zien is er sowieso weinig zinnigs aan op te merken.
Om het geheugengebruik te analyseren en de hoeveelheid tijd dat je script draait (welke functie het langst loopt etc) zou je Xdebug kunnen gebruiken om je code door een profiler te halen (in combinatie met KCacheGrind of WinCacheGrind) en te analyseren.
Of je het OOP paradigma juist gebruikt is misschien meer een mening. Ik zou om te beginnen niet direct je member variabelen aan te spreken maar er een get en set functie voor definieren. De variabele kun je dan private houden en zodoende kun je alles via je get en set functies laten lopen, inclusief het gebruik van Exceptions in het geval van het gebruik van verkeerde data.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:07
- Ik zou mijn objecten nooit zelf de DB laten aanspreken

- Ik zou een DAO / Repository gebruiken, die bv een method GetOrderbyId, een method GetOrdersForCustomer, etc... heeft.
Die class haalt dan de nodige records op uit de DB (zo efficient mogelijk), en gaat dan de nodige Order objecten gaan instantieren & opvullen. (Zie ook Data Mapper pattern). Idealiter gebruik je hiervoor een reeds bestaande O/R mapper. Ik weet wel niet wat er op PHP gebied bestaat aan O/R mappers.

Verder heeft jouw probleem niet echt te maken met 'gebruik ik hier OOP juist'. Wat jouw probleem is, is gewoon hoe je het beste en efficientst de gegevens die op een relationele manier zijn opgeslagen in je DB, naar je object-model omzet, en vice versa.
En, zoals je het nu zo doet zoals je beschrijft, vind ik dat geen goede manier, nee. :)

[ Voor 26% gewijzigd door whoami op 07-02-2010 14:20 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

Verwijderd

vmsw schreef op zondag 07 februari 2010 @ 14:04:
PHP:
1
2
3
4
<?php
$order->relatie->volledige_naam; //bijv. "Pieter Vergiet"
$order->product(5)->prijs; //bijv. 500 cent (= 5 euro)
?>
Hey vmsw :)

Voor manipulatie van individuele objecten/rows is jouw methode handig, maar zoals je zelf al aangeeft: Wat nu als je 5000 facturen moet uitlezen en subtotaal bedragen bij elkaar moet optellen?

In dit geval zou het wellicht handig zijn om een aparte klasse te schrijven die niet 1 rij laadt vanuit de mySQL database, maar een SQL query genereert die een n-aantal rijen ophaalt met 1 enkele actie. Je leidt alle klassen (die entiteiten vormen in je datamodel, zoals orders, producten, enzovoort) vervolgens af vanaf deze klasse zodat je vanuit elk object een methode loadAll() kan aanroepen, waarmee je een n-aantal rijen ophaalt uit de desbetreffende tabel. Capiche?

Zo iets:

PHP:
1
2
3
4
5
6
7
8
9
<?php
$order = new order($db);
$order->loadAll(array('nOrderID', 'sProducts', 'nSubTotal'), '100'); //Get 100 rows with only 3 specific columns and store it in the property "all"
$i = 0;
while ($i < count($order->all)) {
  //Do something with each row collected from the database
  $i++;
}
?>

Acties:
  • 0 Henk 'm!

  • vmsw
  • Registratie: Juli 2006
  • Laatst online: 24-02 19:47
krvabo schreef op zondag 07 februari 2010 @ 14:12:
Je kunt je classes zo maken dat je ook objecten aan kunt maken zonder een ID op te geven. Maak daarnaast functies als setId(), setPrice(), setName(), etc of een functie (constructor?) waarmee je alle gegevens in één keer kunt opgeven.

In het deel waar je de lijst wilt maken kun je dan een query doen van meerdere rows, en met een for/foreach/while nieuwe objecten aanmaken zónder steeds de gegevens op te laten halen met een enkele query.
How, dank voor je input, maar je gaat iets verkeerd in richting. Inderdaad heb ik een dergelijke opzet (ik gebruik functie 'voerGegevensIn' die een array accept maar daarin de nieuwe of gewijzigde gegevens. Dit wordt uiteraard in het object gewijzigd. En ook overloading heb ik inderdaad op die manier gebruikt voor de constructor.
TheGrandWazoo schreef op zondag 07 februari 2010 @ 14:16:
[...]


Ik mag hopen dat de database connectie 1 keer wordt opgebouwd en daarna door het hele script wordt gebruikt, totdat het script is afgelopen en weer uit het geheugen verwijderd wordt. De hoeveelheid objecten die je aanmaakt draagt wel bij aan het geheugen gebruik, maar dat zal toch niet dusdanig zijn dat je memory limiet wordt gehaald? Tot zover ik weet is het geheugengebruik verder geoptimaliseerd in PHP 5.3, itt tot 5.2 en lager. Zonder enige code te zien is er sowieso weinig zinnigs aan op te merken.
Om het geheugengebruik te analyseren en de hoeveelheid tijd dat je script draait (welke functie het langst loopt etc) zou je Xdebug kunnen gebruiken om je code door een profiler te halen (in combinatie met KCacheGrind of WinCacheGrind) en te analyseren.
Of je het OOP paradigma juist gebruikt is misschien meer een mening. Ik zou om te beginnen niet direct je member variabelen aan te spreken maar er een get en set functie voor definieren. De variabele kun je dan private houden en zodoende kun je alles via je get en set functies laten lopen, inclusief het gebruik van Exceptions in het geval van het gebruik van verkeerde data.
Databaseklasse is als een object bij de opslag-klasse, en wordt inderdaad 1x opgebouwd, en constant gebruikt. Maar stel, je vraagt een opsomming van de bedragen van alle facturen, dan zullen bijvoorbeeld voor ELKE order de volgende query's uitgevoerd worden:

[sql]
SELECT xxx FROM factuur WHERE id=1
SELECT xxx FROM factuur WHERE id=2
[/sql]
N.B. xxx staat voor het aantal velden die nodig zijn.

Dit omdat elk object voor zichzelf de gegevens opvraagt.

Verder gebruik ik inderdaad een private array voor de opslag van gegevens.

Ik wil best de code laten zien, maar dit is inmiddels heel erg veel, en omdat ik alles zo handig (logisch) mogelijk wil hebben, en bijvoorbeeld maar op één plek wil definiëren welke gegevens bij bepaalde entiteiten horen, is het vrij ingewikkeld en vol met verwijzingen. Ik vermoed dat het erg vervelend/moeilijk gaat worden om je snel te verdiepen.
whoami schreef op zondag 07 februari 2010 @ 14:19:
- Ik zou mijn objecten nooit zelf de DB laten aanspreken
Gebeurt niet. Gaat via opslag-klasse die meestal gebruik maakt van een object van de sql-klasse
- Ik zou een DAO / Repository gebruiken, die bv een method GetOrderbyId, een method GetOrdersForCustomer, etc... heeft.
Doe ik eigenlijk ook. Bijv. 'new order(5) zal de order met id 5 voorstellen. Als ik daarna zal vragen order(5)->bedrag, dan krijg ik daarmee het bedrag van die order 5. Dat haalt hij (zodra ik dit vraag) uit de database, samen met de overige ordergegevens. Immers moet de query toch al uitgevoerd worden.
Verwijderd schreef op zondag 07 februari 2010 @ 14:24:
[...]
In dit geval zou het wellicht handig zijn om een aparte klasse te schrijven die niet 1 rij laadt vanuit de mySQL database, maar een SQL query genereert die een n-aantal rijen ophaalt met 1 enkele actie. Je leidt alle klassen (die entiteiten vormen in je datamodel, zoals orders, producten, enzovoort) vervolgens af vanaf deze klasse zodat je vanuit elk object een methode loadAll() kan aanroepen, waarmee je een n-aantal rijen ophaalt uit de desbetreffende tabel. Capiche?
Dus eigenlijk een klasse die een 'lijst' bijhoudt. Nadeel is dan wel dat alle gegevens naar php (het geheugen) gezet worden, en niet efficiënt in SQL blijven staan. Immers moet dan alles omgezet worden naar een array.
Maar het klinkt inderdaad wel als aardige methodes, al heb je dan minder aan de entiteiten zoals 'relatie' etc.

[ Voor 21% gewijzigd door vmsw op 07-02-2010 14:34 ]


Acties:
  • 0 Henk 'm!

  • TheGrandWazoo
  • Registratie: Januari 2009
  • Laatst online: 20:24
Waarom voer je de query niet als volgt uit:
SELECT * FROM factuur WHERE id IN(1,2,...,n);

Dan heb je alle id's in 1 query en de resultaten ook.

[ Voor 3% gewijzigd door TheGrandWazoo op 07-02-2010 14:29 ]


Acties:
  • 0 Henk 'm!

  • vmsw
  • Registratie: Juli 2006
  • Laatst online: 24-02 19:47
TheGrandWazoo schreef op zondag 07 februari 2010 @ 14:28:
Waarom voer je de query niet als volgt uit:
SELECT * FROM factuur WHERE id IN(1,2,...,n);

Dan heb je alle id's in 1 query en de resultaten ook.
Dan krijg je de output in de vorm van een array, en niet in de vorm van objecten. Mij leek het leuk (eigenlijk logisch) om constant te werken met objecten. Of denk ik nu verkeerd, als het gaat om bijvoorbeeld lijsten?

[ Voor 6% gewijzigd door vmsw op 07-02-2010 14:31 ]


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 12-09 10:03

Creepy

Tactical Espionage Splatterer

(jarig!)
Voor het opvragen van bijv. een totaal van alle facturen, hoef je natuurlijk niet alle gegevens van alle facturen op te halen. Voor dit soort queries is het wat mij betreft handiger om direct een query te maken die direct de juiste totalen ophaalt. Zo laat je de database voor je rekenen en krijg je i.p.v. alle facturen hoogstens alleen dat totaal uit je query. En dat scheelt een hoop geheugen en snelheid.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • TheGrandWazoo
  • Registratie: Januari 2009
  • Laatst online: 20:24
Je kan toch zelf objecten maken van de resultaten lijst? Je voert 1 query uit en je transformeert het naar een datatype die voor jou erg prettig werkt. In dit geval een object (als je dat wil).

Ik weet niet echt of je verkeerd denkt of niet. Ik heb mijzelf aangeleerd om alle database meuk over te dragen aan een ORM. Die zijn er voor gemaakt en weten het toch altijd beter ;-). Ik gebruik het in combinatie met Doctrine of Propel.

Een ORM is ongeveer dit:
ORM, or Object Relational Mapping, is a database design approach that simplifies managing complex databases for programmers. Instead of direct database access, an ORM layer in a PHP framework can make “objects” stored in a database behave like actual objects from a programming perspective – for example, creating a new “car” stored in the database could involve a call to $car->new(). By abstracting actual database access, web development can be more productive and result in more reliable applications. Here’s a quick intro to ORM in PHP.

ORM brings data closer to a programming paradigm, where actual information is stored and accessed through interfaces that resemble actual objects. In PHP frameworks, this is typically achieved through the framework providing classes representing database information, that can then be manipulated as actual objects such as a car or a booking. This is almost always a level above actual database operations – when using an ORM layer, writing actual SQL queries is taken care of, although an understanding of how to is always helpful.

[ Voor 61% gewijzigd door TheGrandWazoo op 07-02-2010 14:35 ]


Acties:
  • 0 Henk 'm!

  • TheGrandWazoo
  • Registratie: Januari 2009
  • Laatst online: 20:24
Creepy schreef op zondag 07 februari 2010 @ 14:32:
Voor het opvragen van bijv. een totaal van alle facturen, hoef je natuurlijk niet alle gegevens van alle facturen op te halen. Voor dit soort queries is het wat mij betreft handiger om direct een query te maken die direct de juiste totalen ophaalt. Zo laat je de database voor je rekenen en krijg je i.p.v. alle facturen hoogstens alleen dat totaal uit je query. En dat scheelt een hoop geheugen en snelheid.
Soms wil je wat meer gegevens dan alleen het totaal lijkt mij :). Om in dit geval inzicht te geven aan de gebruiker waar de totalen vandaan komen, maar dan heb je wel meer gegevens nodig van de factuur. Verder heb je wel gelijk. Laat de database voor je rekenen als het kan.

Acties:
  • 0 Henk 'm!

  • Ramon
  • Registratie: Juli 2000
  • Laatst online: 22:10
Als ik het probleem goed begrijp, zou jij geholpen zijn met iets als 'unbindModel' uit het CakePHP framework. In CakePHP kan je dus aangeven dat je bij het opvragen van orders, geen informatie van klanten of producten mee wilt nemen, hiermee kan je dus besparen op database load.

Check mijn V&A ads: https://tweakers.net/aanbod/user/9258/


Acties:
  • 0 Henk 'm!

  • krvabo
  • Registratie: Januari 2003
  • Laatst online: 11-09 22:10

krvabo

MATERIALISE!

vmsw schreef op zondag 07 februari 2010 @ 14:25:
[...]

How, dank voor je input, maar je gaat iets verkeerd in richting. Inderdaad heb ik een dergelijke opzet (ik gebruik functie 'voerGegevensIn' die een array accept maar daarin de nieuwe of gewijzigde gegevens. Dit wordt uiteraard in het object gewijzigd. En ook overloading heb ik inderdaad op die manier gebruikt voor de constructor.
Mag ik weten hoe ik precies fout zit in mijn gedachtengang?
Volgens mij heb je zoiets:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Order {

  public $iId; // hier kun je het best privates van maken, met getters en setters
  public $sName; // maar gezien je zegt dat je al veel code hebt.. laat het voor de volgende keer
  public $dPrice;

  public function __construct($iId, $sName = null, $dPrice = null) { 

    $this->iId = $iId;
    
    $this->getById();
  }

}


En je doet dan zoiets:

PHP:
1
2
3
4
5
6
7
8
$aResults = $oDatabase->query('select * from orders where klantid=12', DB_MODE_ROWS);

$aOrders = Array();

foreach($aResults as $aResult) {

  $aOrders[] = new Order($aResult['id']);
}

?

Als dat zo is dan werkt mijn manier wel. Zorg dat je objecten aan kunt maken zonder dat hij een databasequery afvuurt en dan kun je zoiets gebruiken:

PHP:
1
2
3
4
5
6
7
8
$aResults = $oDatabase->query('select * from orders where klantid=12', DB_MODE_ROWS);

$aOrders = Array();

foreach($aResults as $aResult) {

  $aOrders[] = new Order($aResult['id'], $aResult['name'], $aResult['price']);
}


Dit kun je dan dus ook doen voor de producten (die sla je dan op met een private array-variabele in je class Order) en relaties (ditto). Deze vul je gewoon op dezelfde manier:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Order {

  public $iId; // hier kun je het best privates van maken, met getters en setters
  public $sName;
  public $dPrice;

  private $aProducts = array();
  private $aCustomers = array();

  public function __construct($iId, $sName = null, $dPrice = null) { 
 
    if ($sName == null && $dPrice == null) {
    
      $this->getById();
 
    } else {

      $this->sName = $sName;
      $this->dPrice = $dPrice;

    } 
  }

  public function setProducts($uVar) {
    $this->uVar = $uVar;
  }

  public function getProducts() {
    if (empty($aProducts)) {
      $this->getProductsFromDb();
    }
    return $aProducts
  }

}





Wacht, ik denk dat ik je snap.. Als je me gewoon had verteld waar ik anders dacht dan had ik deze moeite niet hoeven doen om het uit te typen..
Je bedoelt dat bij het ophalen van die lijst met orders meteen ook de producten en klanten worden opgehaald? Dan blijf je met mijn oplossing alsnog goed.

Je moet gewoon zorgen dat je alle objecten kunt aanmaken zonder dat er iets uit de database wordt gehaald. Als je de producten al in de lijst wil laten zien, tegelijk met de orders, dan kun je het beste twee queries doen (één voor alle orders, en één voor alle producten met:
SQL:
1
WHERE orderid IN (1,34,546,23)

) en dan met php gaan matchen.

Pong is probably the best designed shooter in the world.
It's the only one that is made so that if you camp, you die.


Acties:
  • 0 Henk 'm!

  • vmsw
  • Registratie: Juli 2006
  • Laatst online: 24-02 19:47
Nja, wat eigenlijk hetgeen is wat ik wil (in mijn hoofd heb), is dat ik constant met objecten werk. Ik ben nu mezelf aan het inlezen op doctrine, want als ik het goed begrijp is dit eigenlijk een database die de objecten opslaat. Klinkt simpel, maar ik vind het minder netjes lijken dan SQL.

Waarom ik het momenteel zo doe, en niet functies maak als "berekenTotaalBedragFacturen()", is omdat ik in de uiteindelijk code het netter/mooier vindt om dit op andere manieren te maken, zoals:

PHP:
1
2
3
4
foreach($administratie->orders as $order)
{
echo $order->bedrag.'<br />';
}


In dat geval werk je constant met objecten (dus vooral ook heel 'simpel' denken), en niet met allerlei gespecialiseerde functies.

Want stiekem ben ik ook zo erg dat ik bijvoorbeeld een abstracte klasse heb 'entiteit' die eigenlijk ALLE functies bevat, waardoor de subklassen relatie en order eigenlijk niks bevatten. Zelfs niet de gegevens over welke velden erin zitten, want die staan in de configuratieklasse... Alles werkt zoveel mogelijk met variabelen, zodat er maar één plek is waar de "instellingen" gedaan worden.
Voor het toevoegen van een faxnummerveld, hoef ik dan ook alleen naam = 'fax' en type = 'telefoonnummer' in te vullen in de configuratieklasse, waarna vervolgens in de overige klassen formuliervelden hiervoor gegenereerd worden, en ook deze gegevens in tabellen etc. gebruikt worden...

Gevolg is dat het hierdoor te gecompliceerd wordt om even 'een stukje code' online te zetten. Dit is voor jullie teveel leeswerk, en tenzij iemand echt geïnteresseerd is lijkt me dit dan ook onhandig. Als iemand wil inzien en commentaar wil geven, dan mag hij/zij dat best mailen of msn'en, maar ik betwijfel het.
krvabo schreef op zondag 07 februari 2010 @ 14:42:
[...]
Je moet gewoon zorgen dat je alle objecten kunt aanmaken zonder dat er iets uit de database wordt gehaald. Als je de producten al in de lijst wil laten zien, tegelijk met de orders, dan kun je het beste twee queries doen (één voor alle orders, en één voor alle producten met:
SQL:
1
WHERE orderid IN (1,34,546,23)

) en dan met php gaan matchen.
Oke. Maar dus alles van SQL naar PHP variabelen zetten. Waardoor er (zodra je een lijst van orders opvraagt puur voor de ordernummers) opeens ook veel productgegevens in het geheugen geladen worden.

Overigens wat ik nu heb is het volgende:

abstracte klasse 'entiteit' met daarin onder andere functies:
- voerGegevensIn (array entiteitsgegevens) //kan door database gebruikt worden voor het inladen van gegevens, maar ook voor het inladen van een ID.
- voerIn(string veld, mixed waarde) // veld = bijv. 'BTWNummer'
- valideer(string veld, mixed waarde)
- haalGegevensOp(void) //maakt contact met opslag-klasse om bij dat id de gegevens op te halen.

en klassen als
relatie extends entiteit met daarin alleen de relatie-onderdeel-validatie-functies (zoals valideerBTWnummer)
relatie extends orders met bijv. valideerOrder (controle of gegevens volledig zijn)

[ Voor 28% gewijzigd door vmsw op 07-02-2010 14:53 ]


Acties:
  • 0 Henk 'm!

  • TheGrandWazoo
  • Registratie: Januari 2009
  • Laatst online: 20:24
vmsw schreef op zondag 07 februari 2010 @ 14:45:
Nja, wat eigenlijk hetgeen is wat ik wil (in mijn hoofd heb), is dat ik constant met objecten werk. Ik ben nu mezelf aan het inlezen op doctrine, want als ik het goed begrijp is dit eigenlijk een database die de objecten opslaat. Klinkt simpel, maar ik vind het minder netjes lijken dan SQL.
Het is geen database, maar een laag tussen jou code en je database structuur. De ORM zorgt ervoor dat alle SQL queries worden uitgevoerd en levert je objecten terug, gemodelleerd naar je database structuur. Zo kun je dus objecten gegevens uit je database krijgen (en zo complex maken als je zelf wilt) of in je database zetten op een uniforme manier zonder dat je al teveel tijd kwijt bent aan het schrijven van queries en code om de resultaten van die queries om te zetten in objecten of arrays.

Acties:
  • 0 Henk 'm!

  • vmsw
  • Registratie: Juli 2006
  • Laatst online: 24-02 19:47
TheGrandWazoo schreef op zondag 07 februari 2010 @ 14:48:
[...]


Het is geen database, maar een laag tussen jou code en je database structuur. De ORM zorgt ervoor dat alle SQL queries worden uitgevoerd en levert je objecten terug, gemodelleerd naar je database structuur. Zo kun je dus objecten gegevens uit je database krijgen (en zo complex maken als je zelf wilt) of in je database zetten op een uniforme manier zonder dat je al teveel tijd kwijt bent aan het schrijven van queries en code om de resultaten van die queries om te zetten in objecten of arrays.
Verbazingwekkend. Mijn klasse 'entiteit' (abstract voor bijv. relatie en order) doet bijna hetzelfde. Alleen dit in samenwerking met de opslag en SQL klasse. De functies zijn bijna hetzelfde, bijvoorbeeld merge == voerGegevensIn, en save == doorvoeren.. Verder ook de subobjecten worden opeenzelfde manier gevormd.
Zelfs de SQL-geschiktheidsvalidaties worden uitgevoerd :P.

Ik heb eigenlijk iets gemaakt dat al bestaat, en wellicht daar beter is.. Echter lijkt me het dan prettiger om toch maar door te gaan, aangeizen mijn stadium vrij ver is inmiddels, en ik anders de complete basis moet omgooien.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:07
vmsw schreef op zondag 07 februari 2010 @ 14:25:
[...]
Gebeurt niet. Gaat via opslag-klasse die meestal gebruik maakt van een object van de sql-klasse

[...]

Doe ik eigenlijk ook. Bijv. 'new order(5) zal de order met id 5 voorstellen. Als ik daarna zal vragen order(5)->bedrag, dan krijg ik daarmee het bedrag van die order 5. Dat haalt hij (zodra ik dit vraag) uit de database, samen met de overige ordergegevens. Immers moet de query toch al uitgevoerd worden.
Dus, jouw domain classes spreken toch -zei het onrechtstreeks, omdat jouw domain class jouw sql class aanspreekt- de DB aan. Jouw domain classes hebben een dependency met de DB.
Zou ik nooit doen.
Ipv
code:
1
Order o = new Order(5)

Zou ik dus eerder iets doen als:
code:
1
Order o = OrderRepository.GetOrderById (5);
Dus eigenlijk een klasse die een 'lijst' bijhoudt. Nadeel is dan wel dat alle gegevens naar php (het geheugen) gezet worden, en niet efficiënt in SQL blijven staan. Immers moet dan alles omgezet worden naar een array.
Waarom zou je dat doen ? Je 'lijst' wordt in je DB bijgehouden. Je haalt gewoon de gevraagde objecten op.

code:
1
Order[] orders = OrderRepository.GetOrdersForCustomer (customer);

Die method gaat gewoon een SQL statement uitvoeren, je zorgt ervoor dat je de gegevens zoals je die krijgt van de DB mapt naar de nodige order objecten, en klaar is kees.
Maar het klinkt inderdaad wel als aardige methodes, al heb je dan minder aan de entiteiten zoals 'relatie' etc.
Waarom ?
Creepy schreef op zondag 07 februari 2010 @ 14:32:
Voor het opvragen van bijv. een totaal van alle facturen, hoef je natuurlijk niet alle gegevens van alle facturen op te halen. Voor dit soort queries is het wat mij betreft handiger om direct een query te maken die direct de juiste totalen ophaalt. Zo laat je de database voor je rekenen en krijg je i.p.v. alle facturen hoogstens alleen dat totaal uit je query. En dat scheelt een hoop geheugen en snelheid.
Inderdaad, voor dergelijke functionaliteit haal ik meestal ook geen entities op, maar 'View' objecten, of DTO instances ('t is maar hoe je ze wil noemen), die dus enkel de gegevens bevatten die nodig zijn.
Vanaf daar kan je dan, indien gewenst natuurlijk wel voor een bepaald item de volledige entity gaan ophalen indien nodig.

[ Voor 50% gewijzigd door whoami op 07-02-2010 22:20 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 12-09 10:54

Janoz

Moderator Devschuur®

!litemod

Misschien is Datalaag opzet* ook wel even leuk ter inspiratie.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:07
vmsw schreef op zondag 07 februari 2010 @ 14:45:
Nja, wat eigenlijk hetgeen is wat ik wil (in mijn hoofd heb), is dat ik constant met objecten werk. Ik ben nu mezelf aan het inlezen op doctrine, want als ik het goed begrijp is dit eigenlijk een database die de objecten opslaat. Klinkt simpel, maar ik vind het minder netjes lijken dan SQL.

Waarom ik het momenteel zo doe, en niet functies maak als "berekenTotaalBedragFacturen()", is omdat ik in de uiteindelijk code het netter/mooier vindt om dit op andere manieren te maken, zoals:

PHP:
1
2
3
4
foreach($administratie->orders as $order)
{
echo $order->bedrag.'<br />';
}
Tja, als je het 'puur OO' wilt aanpakken, dan ga je zeker ook op beperkingen botsen. Je moet pragmatischer denken.
Je kan voor bepaalde situaties ook een 'Service' object maken, waarin je bv een method als 'berekenTotaalBedragFacturenVoorKlant(x) kunt huisvesten.
In dat geval werk je constant met objecten (dus vooral ook heel 'simpel' denken), en niet met allerlei gespecialiseerde functies.
2 situaties:
- ofwel denk je constant in objecten dat je om bepaalde problemen op te lossen, steeds omwegen moet verzinnen, zodanig dat het verre van simpel denken is
- ofwel zal je op termijn op gigantische performance problemen botsen.
Want stiekem ben ik ook zo erg dat ik bijvoorbeeld een abstracte klasse heb 'entiteit' die eigenlijk ALLE functies bevat, waardoor de subklassen relatie en order eigenlijk niks bevatten.
Slecht bezig imho.
Niet iedere entity zal nl. altijd al die functionaliteit nodig hebben, en dan zaai je weer verwarring.
Later een aanpassing doorvoeren zal ook moeilijker worden.
Volgens mij ben je de boel gewoon onnodig complex aan het maken; je moet de juiste functionaliteit bij de juiste classes onderbrengen.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Ssander
  • Registratie: December 2009
  • Laatst online: 12-06-2023
De volgende link is misschien ook wel interessant om naar te kijken;

http://martinfowler.com/eaaCatalog/

Ik kreeg het idee dat je niet heel veel van design patterns afweet, dus vandaar. Vooral de 'Data Source Architectural Patterns' zijn voor jouw probleem wel interessant.

Wat je eigenlijk vooral moet doen is verschil maken tussen heb object zelf (de order) en een object om dit order uit de database te halen. Dat laatste wordt het 'ORM' genoemd, het object zelf Data Object of Property Object. Maak een repository, een gateway, een mapper of iets dergelijks (staan allemaal op die pagina) en laat deze data objecten aanmaken. De database logica wil je dus scheiden van je opslag object, niet combineren zoals jij doet. Dit combineren leidt tot meerdere problemen waarvan jij er één van bent tegengekomen :)

Acties:
  • 0 Henk 'm!

  • vmsw
  • Registratie: Juli 2006
  • Laatst online: 24-02 19:47
Oke, dank voor jullie commentaar.

Ik zal het minder 'strict' OOP-achtig maken, en weer opnieuw makkelijker denken met standaardfuncties voor diverse onderdelen. Ik zie zelf inderdad nu ook wel in dat alles in objecten wel erg zwaar zou worden.

Dank voor de feedback!
Pagina: 1