OO lijsten

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Jeroen VD

Jeroen VD

10/04/2012 15:56:52
Quote Anchor link
ik zit vast met het volgende:

hoe maak ik een lijst met OOP?
ik ben bezig met een intern mailsysteem, daar worden berichten opgeslagen in de database. dan heb ik een Mail_Processor class, die de benodigde data ophaalt uit de database, wat bewerkt etc (bv een method om het aantal nieuwe mailtjes te tonen, 1 specifieke mail op te halen, etc)

nu wil ik dus ook, net als in elke mailbox, een lijst met alle mails (en dan alleen afzender + onderwerp ofzo). maar hoe pak ik dat aan? ik had zelf gedacht om alle resultaten op te halen, html van maken in een var, en dat dan returnen. maar dat lijkt me niet echt netjes etc. en het volgende probleem is dan daaraan pagination toevoegen, dat er max 15 berichten op elke pagina staan. hoe doe ik dat op een goede manier?
 
PHP hulp

PHP hulp

11/01/2025 01:05:21
 
Wouter J

Wouter J

10/04/2012 16:06:11
Quote Anchor link
Je hebt als het goed is een MessageMapper die de connectie tussen object en DB verzorgt. Deze MessageMapper bevat dan een method MessageMapper::getAll() en die geeft een array met message objects terug.
Met de pagination of wat er met de array gedaan wordt mag de MessageMapper helemaal niet weten. Voor Pagination heb je een eigen klasse en hoe het op het scherm komt beslis je in een View klasse of via procedurele code.

Globaal wordt het iets van dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
$messageMapper
= new MessageMaper();

$messagesPagination = new Pagination($messageMapper->getAll());
$messagesPagination->setMaxPerPage(15);
?>

<ul id="messages">
<?php foreach ($messagesPagination->getPage(1) as $message) : ?>
  <li><a href="show_message.php?id=<?php echo $message->getId(); ?>"><?php echo $message->getName(); ?></a></li>
<?php endforeach ?>
</ul>
 
Jeroen VD

Jeroen VD

10/04/2012 16:11:19
Quote Anchor link
hmm ok, maar de Mail_Processor class (zie hieronder) is praktisch alleen maar database bewerkingen. daarom had ik ook besloten om dit in 1 class te doen. dat zou ik dus om moeten gooien naar bovenstaand voorbeeld?
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?php
    class Mail_Processor
    {
        private $_db;
        private $_userId;
        
        public __construct(PDO $db, $userId)
        {

            $this->_db = $db;
            $this->_userId = $userId;
        }

        
        public function sendMail($desUser, $message, $subject)
        {

            $getDesUserId =
                "SELECT
                    user_id
                FROM
                    users
                WHERE
                    user_id = :desUser"
;
            $stmt = $this->_db->prepare($getDusUserId);
            $results = $stmt->exec(array(':desUser' => $desUser))->fetch();
            if (count($results) != 1)
            {

                return 'Recepient does not exist';
            }

            else
            {
                $desUserId = $results['user_id'];
                $insertMail =
                    "INSERT INTO
                        messages
                            (desUser_id,
                            senUser_id,
                            subject,
                            message,
                            dateAndTime,
                            new)
                    VALUES
                        (:desUser,
                        :senUser,
                        :subject,
                        :message,
                        NOW(),
                        1)"
;
                $stmt = $this->_db->prepare($insertMail);
                $inserted = $stmt->exec(':desUser' => $desUserId,
                                        ':senUser' => $this->_userId,
                                        ':subject' => $subject,
                                        ':message' => $message);
                if ($inserted != 1)
                {

                    return 'something went wrong. please try again';
                }

                else
                {
                    return 'your mail was succesfully sent!';
                }
            }
        }

        
        public function NewMails()
        {

            $newMails =
                "SELECT
                    COUNT(message_id) AS mails
                FROM
                    messages
                WHERE
                    new = 1
                AND
                    desUser_id = :userId"
;
            $stmt = $this->_db->prepare($newMails);
            $mails = $stmt->exec(array(':userId' => $this->_userId))->fetch();
            return $mails['mails'];
        }

        
        public function listMails($results, $start)
        {
            
        }

        
        public function showMail($messageId)
        {

            $getMail =
                "SELECT
                    users.username AS sender,
                    messages.subject AS subject,
                    messages.message AS message,
                    DATE_FORMAT(messages.dateAndTIme, '%d-%m-%Y at %H:%i') AS time_sent
                FROM
                    messages,
                    users
                WHERE
                    messages.message_id = :messageId
                AND
                    users.user_id = messages.senUser_id"
;
            $stmt = $this->_db->prepare($getMail);
            $mails = $stmt->exec(array(':messageId' => $messageId))->fetch();
            if (count($mails) != 1)
            {

                return 'something went wrong. please try again';
            }

            else
            {
                $updateNew =
                return array('sender' => $mails['sender'],
                             'subject' => $mails['subject'],
                             'message' => $mails['message'],
                             'time_sent' => $mails['time_sent']);
            }
        }
    }

?>
 
Wouter J

Wouter J

10/04/2012 16:14:59
Quote Anchor link
Hmm, wat je nu hebt is niet heel erg OO achtig. Het object Mail_Proccesor doet nu ong. wat je in OO in iets van 4 objecten moet doen. Een Object mag niet te veel verantwoordelijkheid krijgen, elke klasse mag maar 1 object hebben. Wat jij nu hebt is dat je in 1 klasse de Message/Mail object hebt, een view object, de MailMapper en een User object + Mapper. Iets teveel dus.

Ik zou eerst beginnen met het maken van UML diagrammen van wat je nou precies wilt en hoe je het nou in objecten moet onderverdelen.
 
Jeroen VD

Jeroen VD

10/04/2012 16:21:40
Quote Anchor link
ik ben volgens mij nog iets te procedureel bezig ja...

maar krijg je volgens jou niet iets als dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php
  public function sendMail($desUser, $message, $subject)
  {

     MailMapper::sendMail($desUser, $message, $subject);
  }

?>


of in de procedurele code een aantal verschillende objecten aanmaken, allemaal met verschillende functies? maar krijg je dan niet precies hetzelfde?
 
Wouter J

Wouter J

10/04/2012 16:34:15
Quote Anchor link
Ik zou ong. zo'n structuur maken:
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
<?php
// User gedoe
$userMapper = new UserMapper();
$user = $userMapper->getById(12);
if (!$user->isLoggedIn()) {
  throw new RunTimeException('U moet wel ingelogd zijn.');
}


// Send Mail
$mailMapper = new MailMapper();
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if (!isset($_POST['message'])) {
         throw new RunTimeException('Er moet wel een bericht ingevuld worden');
    }

    // enz.

    $mail = new Mail($user, $_POST['to'], $_POST['message']);
    if ($mailMapper->sendMail($mail)) {
        echo 'Mail succesvol verzonden';
    }
}

?>
 
Jeroen VD

Jeroen VD

10/04/2012 16:40:09
Quote Anchor link
ik vat m niet helemaal. maak je nu een object mail aan met alleen maar gegegevens, en je geeft die gegevens door aan de mailmapper?
 
Wouter J

Wouter J

10/04/2012 16:51:21
Quote Anchor link
Ja, hierdoor kun je in de MailMapper gebruik maken van bijv. Mail::to() om de persoon waartoe het moet te krijgen, Mail::getContent() voor de content van de mail, enz:
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
<?php
class MailMapper
{
    /* ... */
    public function sendMail(Mail $mail)
    {

        $sQuery = "INSERT INTO messages(user_to, user_from, content, subject) VALUES(:to, :from, :content, :subject)";
        $stmt = $this->db->prepare($sQuery);
        $stmt->execute(array(
          ':to' => $mail->getUserTo(),
          ':from' => $mail->getUserFrom(),
          ':subject' => $mail->getSubject(),
          ':content' => $mail->getContent(),
        ));

        if ($stmt->rowCount() > 0) {
            return true;
        }

        else {
            return new LogicException('<de foutmeldig>');
        }
    }
}

?>
 
Jeroen VD

Jeroen VD

10/04/2012 16:58:09
Quote Anchor link
ok volgens mij snap ik het! zal het eens omschrijven naar bovenstaand, om zo dus iets moois te krijgen. bedankt voor de mooie uitleg!
 
Jeroen VD

Jeroen VD

12/04/2012 16:52:16
Quote Anchor link
ik kom er toch niet helemaal uit. ik heb nu een Message class gemaakt, en een MessageMapper. de user komt nog in andere classes. zie code hieronder

message.class.php:
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
<?php
    class Message
    {
        //int, sender (sender user id)
        private $_senUserId;
        
        //int, recepient (destination user id)
        private $_desUserId;
        
        //string, message content
        private $_content;
        
        //string, message subject
        private $_subject;
        
        //string, date & time message was sent
        private $_dateTime;
        
        public function __construct($SenUserId, $desUserId, $content, $subject, $dateTime)
        {

            //variable declaration
            $this->_senUserId = $senUserId;
            $this->_desUserId = $desUserId;
            $this->_content = $content;
            $this->_subject = $subject;
            $this->_dateTime = $dateTime;
        }

        
        public function getSenUserId()
        {

            return $this->_senUserId;
        }

        
        public function getDesUser()
        {

            return $this->_desUser;
        }

        
        public function getContent()
        {

            return $this->_content;
        }

        
        public function getSubject()
        {

            return $this->_subject;
        }

        
        public function getDateTime()
        {

            return $this->_dateTime;
        }
    }

?>


MessageMapper.class.php:
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
60
61
62
63
64
65
66
67
68
<?php
    class MessageMapper
    {
        //object, database connection
        private $_db;
        
        public function __construct(PDO $db)
        {

            //variable declaration
            $this->_db = $db;
        }

        
        public function sendMessage(Messsage $message)
        {

            $sendMessage =
                "INSERT INTO
                    messages
                        (desUser_id,
                        senUser_id,
                        subject,
                        message,
                        dateAndTime,
                        new)
                VALUES
                    (:desUser,
                    :senUser,
                    :subject,
                    :message,
                    NOW(),
                    1)"
;
            $stmt = $this->_db->prepare($sendMessage);
            $inserted = $stmt->exec(
                                ':desUser' => $message->getDesUser(),
                                ':senUser' => $message->getSenUser(),
                                ':subject' => $message->getSubject(),
                                ':message' => $message->getContent());
            if ($inserted != 1)
            {

                return 'something went wrong. please try again';
            }

            else
            {
                return 'your mail was succesfully sent!';
            }
        }

        
        public function recieveMessage($messageId, $desUserId)
        {

            $receiveMessage =
                "SELECT
                    subject,
                    message,
                    senUser_id
                    DATE_FORMAT(messages.dateAndTIme, '%d-%m-%Y at %H:%i') AS time_sent
                FROM
                    messages
                WHERE
                    desUser_id = :desUserId
                AND
                    message_id = :messageId"
;
            $stmt = $this->_db->prepare($receiveMessage);
            $stmt->exec(
                    ':desUserId' => $messageId,
                    ':senUser' => $desUserId);
            //en dan?!!
        }
    }

?>


dan heb ik twee vragen die volgens mij hetzelfde antwoord hebben:
- hoe return ik die waarden op regel 65?
- hoe return ik heel veel van die waarden (dus in een lijst)?

ikzelf dacht aan (in de MessageMapper) een Message te instantieren. in beide gevallen, bij de tweede in een loop een array vullen. maar dat is niet de OOP gedachte, toch? maar hoe doe ik dat dan?
 
Wouter J

Wouter J

12/04/2012 17:05:01
Quote Anchor link
Je moet een array returnen. Iets als dit:
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
<?php
class MessageMapper
{
    /* ... */

    public function getMessages(...)
    {

        /* ... */
        $result = $stmt->fetchAll();
        return array_map(array($this, 'populate'), $result);
    }


    public function populate($data)
    {

        return new Message($data['subject'], $data['message'], $data['senUser_id'], $data['send_time']);
    }
}


$messageMapper = new MessageMapper();
?>

<!-- HTML -->
<dl>
    <?php foreach ($messageMapper->getMessages() as $message) : ?>
    <dt><?php echo $message->getSubtitle() ?></dt>
    <dd><?php echo $message->getContent() ?></dd>
    <?php endforeach ?>
</dl>


Verder ziet het er heel mooi en goed OOP uit!!
Nog een mooi, en leerzaam, voorbeeldje van Pim: http://www.phphulp.nl/php/forum/topic/oop-in-combinatie-met-database/81754/#580025
Gewijzigd op 12/04/2012 17:08:38 door Wouter J
 
Jeroen VD

Jeroen VD

12/04/2012 17:10:00
Quote Anchor link
maakt array_map() een object aan, of doet de populate functie dat? en dan moet ik toch een include doen naar message.class.php, en dat gaat dan verloren aan de flexabiliteit? dit zou in ieder geval een hoop oplossen. array_map() kende ik niet. bedankt!

btw, wat vind je van mn classes?
 
Wouter J

Wouter J

12/04/2012 17:15:15
Quote Anchor link
Array_map loopt door elk array item en voert de callback uit op dat array item:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
$i
= 0;
$titles = array('Hello world', 'lorem ipsum', 'foobar', 'phphulp is goed');
$titles = array_map(function($str) {
  return ++$i.' '.$titles;
},
$titles);
foreach($titles as $title)
  echo $title; // 1. Hello world | 2. Lorem ipsum | 3. foobar | 4. phphulp is goed
?>


Als je array($this, 'populate') gebruikt wordt de callback functie de populate method van de klass waar je in zit. De populate method maakt dus van bepaalde gegevens een object.

En een datamapper is afhankelijk van het object dat je gebruikt dus er gaat geen flexibiliteit verloren, anders kan het ook niet. Daarnaast hoef je een klasse maar 1 keer per aanroep te includen (of eigenlijk liever te requireren).
 
Jeroen VD

Jeroen VD

12/04/2012 18:13:04
Quote Anchor link
ik begrijp het niet helemaal, maar begrijp wel wat ik ermee kan, en ik kan dit gebruiken. is het trouwens niet beter om de visibility van de populate method op protected te zetten?
 
Wouter J

Wouter J

12/04/2012 18:18:29
Quote Anchor link
Nee, je kan het ook gebruiken als je data uit bijv. een form haalt om dat om te zetten in een member object: (de messagemapper wordt dan een soort service container)
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    /* ... */

    $newMessage = $messageMapper->populate(array(
        $_POST['subject'],
        $_POST['message'],
        date('c'),
    ));
}

?>


Wat begrijp je dan niet? Code die je niet begrijpt moet je niet gebruiken vind ik altijd.
Gewijzigd op 12/04/2012 18:19:39 door Wouter J
 
Jeroen VD

Jeroen VD

12/04/2012 18:26:19
Quote Anchor link
'de callback op dat array item' -> vrij cryptisch, heb maar een vaag idee wat een callback is, daarom.
dat ik hem wel gebruik is omdat ik wel begrijp wát het doet, alleen het hoe blijft een klein raadsel

en dat ik het kon gebruiken als 'service container' (-> ook al zo'n leuke OO term, ik wacht op de tutorial van pim ;-)) is natuurlijk handig, en had ik helemaal niet aan gedacht

Toevoeging op 12/04/2012 18:35:10:

die link die je nog geplaatst had (over het hoofd gezien) had je al eerder gegeven. heb ik inderdaad veel van geleerd :)
 
Wouter J

Wouter J

12/04/2012 19:14:24
Quote Anchor link
Quote:
(-> ook al zo'n leuke OO term, ik wacht op de tutorial van pim ;-)

Hoeft niet, is er al: Dependency Injection

Quote:
'de callback op dat array item' -> vrij cryptisch, heb maar een vaag idee wat een callback is, daarom.

De callback is de functie die wordt aangeroepen nadat iets wordt gedaan. In dit geval doet de array_map functie zoiets:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php
function array_map($callback, $array)
{

    foreach ($array as $arrayItem) {
        $callback($arrayItem);
    }
}

?>

De callback is een functie (in dit geval MessageMapper:populate()) en die wordt per array items aangeroepen met als parameter de value of het item.
De functie die wordt aangeroepen is de callback.

Offtopic:
Dit heb je bijv. ook in JS, vooral in jQuery kan het flink oplopen: http://jsfiddle.net/fnUaq/
 
Jeroen VD

Jeroen VD

12/04/2012 21:18:40
Quote Anchor link
Aah nou snap ik hem ;) bedankt voor je lange uitleg!
 



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.