[OOP] Van een object naar lijsten met meerdere objecten

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Ward van der Put
Moderator

Ward van der Put

12/09/2013 09:01:49
Quote Anchor link
Voor een webwinkelplatform heb ik een class Product, die nu een active record pattern volgt. Elk product heeft tientallen eigenschappen, die met uiteenlopende beslissingsregels in Product::select() worden ingesteld. Ingekort voor drie eigenschappen en twee beslissingsregels ziet de klasse er zo uit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
class Product implements ActiveRecordInterface
{
    private $ProductID;
    private $Name;
    private $Price;
    // Enzovoort...

    public function __construct($id = null)
    {

        if (isset($id)) {
            $this->select($id);
        }
    }


    /**
     * @param int $id
     * @return bool
     */

    public function select($id)
    {

        if (is_numeric($id) && $id <= PHP_INT_MAX) {
            $id = (int) abs($id);
        }
else {
            return false;
        }

        $query = 'SELECT * FROM products WHERE product_id = ' . $id;
        $dbh = new Database();
        if ($result = $dbh->query($query)) {
            if ($result->num_rows == 1) {
                $record = $result->fetch_assoc();
                $result->free();
                $dbh->close();
                unset($result, $dbh);
                $this->ProductID = $id;

                // Beslissingsregels
                if ($record['product_name_nl'] != null) {
                    $this->Name = $record['product_name_nl'];
                }
else {
                    $this->Name = $record['product_name_en_us'];
                }


                if ($record['sale_price'] != null) {
                    $this->Price = (float) $record['sale_price'];
                }
elseif ($record['price'] != null) {
                    $this->Price = (float) $record['price'];
                }
else {
                    $this->Price = null;
                }

                // Enzovoort...

                return true;
            }
        }

        return false;
    }
}

?>

Voor uiteenlopende lijsten met meerdere producten (tabellen, prijslijsten, zoekresultaten, enzovoort) is het onpraktisch om meerdere complete productobjecten te laden die elk een eigen query uit te voeren. Wat is hiervoor een efficiënte oplossing waarbij de beslissingsregels niet verloren gaan?
Gewijzigd op 12/09/2013 09:02:32 door Ward van der Put
 
PHP hulp

PHP hulp

19/04/2024 14:02:25
 
Erwin H

Erwin H

12/09/2013 09:36:48
Quote Anchor link
Om te beginnen zou ik deze class gaan splitsen. Op dit moment heeft deze class meerdere verantwoordelijkheden. Het beheert de product gegevens en bouwt de query. Dat laatste zou niet zijn taak moeten zijn. Die query moet er dus uit en in een aparte class (noem het een datamapper, of query class). En dan heb je je oplossing in feite al. Die query class geeft een array aan producten terug (kan er 1 zijn, kunnen er meerdere zijn) en voor elke element in die array maak je een object van de product class aan. In de constructor van die class geef je een array mee met alle product eigenschappen en daar worden dan de door jouw getoonde tests in uitgevoerd.

Eventueel heb je er dus nog wel een class tussen nodig (wat ik een facade noem), die die product objecten aanmaakt op basis van de array die het krijgt uit de query class.
 
Ward van der Put
Moderator

Ward van der Put

12/09/2013 10:11:22
Quote Anchor link
Dank je Erwin! Ik zocht het te makkelijk in één extra klasse. Met twee klassen lijkt het me inderdaad beter: een datamapper voor de ruwe data plus een façade voor de beslissingsregels.

Een deel van de hardere beslissingsregels hoort inderdaad thuis in een querybuilder. Bijvoorbeeld: bij een product zonder Nederlandse naam gebruiken we altijd de Engelse naam. (Dat is namelijk een IFNULL in SQL.) Zachtere beslissingsregels, bijvoorbeeld price rules, kunnen over naar de façade. Mooie oplossing!

Denk je dat hier nog winst is te behalen met bijvoorbeeld een flyweight pattern?
 
Erwin H

Erwin H

12/09/2013 10:45:38
Quote Anchor link
Ik gebruik inderdaad een flyweight patern voor wat ik noem de 'sanitizers'. Dit zijn objecten die voor de juiste formatering zorgen van bepaalde velden. Bijvoorbeeld datums komen altijd op de MySQL manier uit de database, maar mijn sanitizers zorgen ervoor dat dat op een correcte manier geformateerd wordt (dus niet '2013-09-12 10:43:12' maar '12 September 2013 10:43'). Maar bijvoorbeeld ook voor het afhandelen van lege waardes, of zelfs niet bestaande waardes. Zo hoef ik in mijn view nooit te controleren of een veld wel bestaat of niet. Elke product object (in jouw geval) zou geinjecteerd kunnen worden met een sanitizer en die zorgt voor die formatering, zonder zelf data opgeslagen te hebben.
 
Johnny Reinders

Johnny Reinders

16/09/2013 17:18:55
Quote Anchor link
sorry deze post was niet voor hier had verkeerd geklikt
Gewijzigd op 16/09/2013 17:31:11 door Johnny Reinders
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.