Public and Private Messages [ 222 ] <tr> <th>Sent</th> <td>{inbox_sentFriendlyTime}</td> </tr> <tr> <th>Message</th> <td>{inbox_message}</td> </tr> </table> </div> </div> Mark as read Once a user has read a message, we should update the database to indicate that the message has been read, so that the user can see at a glance which of their messages are new and unread, and which ones have already been read. However, for privacy reasons, we shouldn't show this information to the sender of the message. To do this, we simply set the read property on the model to 1, and save the record, as illustrated by the changes to viewMessage highlighted below: /** * View a message * @param int $message the ID of the message * @return void */ private function viewMessage( $message ) { require_once( FRAMEWORK_PATH . 'models/message.php' ); Download from Wow! eBook <www.wowebook.com> Chapter 7 [ 223 ] $message = new Message( $this->registry, $message ); if( $message->getRecipient() == $this->registry- >getObject('authenticate')->getUser()->getUserID() ) { $this->registry->getObject('template')- >buildFromTemplates('header.tpl.php', 'messages/view.tpl.php', 'footer.tpl.php'); $message->toTags( 'inbox_' ); $message->setRead(1); $message->save(); } else { $this->registry->errorPage( 'Access denied', 'Sorry, you are not allowed to view that message'); } } Now once the user reads a message, the database records the message as having been read. Deleting a message To delete a message, we simply call the model's delete method, provided the message was sent to the logged in user of course! What about the sender? These deletes will remove the message completely, even from the sender, but what if we want to have the sender keep their copy, or have the sender be able to delete their copy? Feel free to extend this to have an additional eld to indicate whether the message has been deleted by the sender, and add the functionality in. /** * Delete a message * @param int $message the message ID * @return void */ private function deleteMessage( $message ) { require_once( FRAMEWORK_PATH . 'models/message.php' ); $message = new Message( $this->registry, $message ); if( $message->getRecipient() == $this->registry- Download from Wow! eBook <www.wowebook.com> Public and Private Messages [ 224 ] >getObject('authenticate')->getUser()->getUserID() ) { if( $message->delete() ) { $url = $this->registry->getObject('url')->buildURL( array(), 'messages', false ); $this->registry->redirectUser( $url, 'Message deleted', 'The message has been removed from your inbox'); } If the message wasn't sent to the logged in user, or if there was a problem deleting the message, we should display an appropriate error message to the user: else { $this->registry->errorPage( 'Sorry ', 'An error occured while trying to delete the message'); } } else { $this->registry->errorPage( 'Access denied', 'Sorry, you are not allowed to delete that message'); } } Composing a new message Composing a new message is the most complicated aspect for the feature, as there are a number of aspects to consider (and change, depending on the needs of the social network). Let's discuss these as we walk through the code: /** * Compose a new message, and process new message submissions * @parm int $reply message ID this message is in reply to [optional] only used to pre-populate subject and recipient * @return void */ private function newMessage( $reply=0 ) { $this->registry->getObject('template')->buildFromTemplates('header. tpl.php', 'messages/create.tpl.php', 'footer.tpl.php'); Download from Wow! eBook <www.wowebook.com> Chapter 7 [ 225 ] The two strands of this feature (displaying the new message form, and processing the new message) require knowing a list of members that the message can be sent to (provided we wish to restrict sending to contacts only). As this is the case, it makes sense for us to require the relationships model, and instantiate it before progressing: require_once( FRAMEWORK_PATH . 'models/relationships.php' ); $relationships = new Relationships( $this->registry ); if( isset( $_POST ) && count( $_POST ) > 0 ) { If the user has submitted a new message, we need to check that the recipient they have selected is in their network (that is, that they are allowed to send them a message): $network = $relationships->getNetwork( $this->registry- >getObject('authenticate')->getUser()->getUserID() ); $recipient = intval( $_POST['recipient'] ); if( in_array( $recipient, $network ) ) { If the recipient is in the user's network, then we create an instance of the message model, populate it with the data the user has submitted, and then save the message and redirect the user after displaying a conrmation message: // this additional check may not be something we require for private messages? require_once( FRAMEWORK_PATH . 'models/message.php' ); $message = new Message( $this->registry, 0 ); $message->setSender( $this->registry- >getObject('authenticate')->getUser()->getUserID() ); $message->setRecipient( $recipient ); $message->setSubject( $this->registry->getObject('db')- >sanitizeData( $_POST['subject'] ) ); $message->setMessage( $this->registry->getObject('db')- >sanitizeData( $_POST['message'] ) ); $message->save(); // email notification to the recipient perhaps?? // confirm, and redirect $url = $this->registry->getObject('url')->buildURL( array(), 'messages', false ); $this->registry->redirectUser( $url, 'Message sent', 'The message has been sent'); } else { Download from Wow! eBook <www.wowebook.com> Public and Private Messages [ 226 ] If the recipient isn't in their network, we display an error page. Alternatively, we could check the recipient's privacy settings to see if they allow messages from any user—something to consider when implementing privacy controls: $this->registry->errorPage('Invalid recipient', 'Sorry, you can only send messages to your recipients'); } } else { If the user hasn't submitted the form, then we need to display the new message form to them. We can get the list of potential recipients (to go in a drop down) from the relationships model, which we associate with a template variable. $cache = $relationships->getByUser( $this->registry- >getObject('authenticate')->getUser()->getUserID() ); $this->registry->getObject('template')->getPage()- >addTag( 'recipients', array( 'SQL', $cache ) ); if( $reply > 0 ) { If the message is in reply to another message, then we can provide some basic support for this, such as pre-selecting the recipient, and pre-completing the subject line based off the message this is in reply to: require_once( FRAMEWORK_PATH . 'models/message.php' ); $message = new Message( $this->registry, $reply ); if( $message->getRecipient() == $this->registry- >getObject('authenticate')->getUser()->getUserID() ) { $this->registry->getObject('template')-> getPage()- >addAdditionalParsingData( 'recipients', 'ID', $message->getSender(), 'opt', "selected='selected'"); $this->registry->getObject('template')->getPage()- >addTag( 'subject', 'Re: ' . $message->getSubject() ); } else { $this->registry->getObject('template')->getPage()- >addTag( 'subject', '' ); } Download from Wow! eBook <www.wowebook.com> Chapter 7 [ 227 ] } else { $this->registry->getObject('template')->getPage()- >addTag( 'subject', '' ); } } } Creating a message template For the new message template (views/default/templates/messages/create. tpl.php) , we have a template loop for possible recipients. If the message is a reply, the recipient is selected via the additionalParsingData set in the controller. The subject is also pre-populated for us: <div id="main"> <div id="rightside"> <ul> <li><a href="messages/">Your inbox</a></a> </ul> </div> <div id="content"> <h1>Compose message</h1> <form action="messages/create" method="post"> <label for="recipient">To:</label><br /> <select id="recipient" name="recipient"> <! START recipients > <option value="{ID}" {opt}>{users_name}</option> <! END recipients > </select><br /> <label for="subject">Subject:</label><br /> <input type="text" id="subject" name="subject" value="{subject}" /><br /> <label for="message">Message:</label><br /> <textarea id="message" name="message"></textarea><br /> Download from Wow! eBook <www.wowebook.com> Public and Private Messages [ 228 ] <input type="submit" id="create" name="create" value="Send message" /> </form> </div> </div> In action If we visit our message centre /messages, we can see our inbox (once the controller is added to the controllers table in the database!), as shown in the screenshots earlier in the chapter. If we click reply, we are taken to the same screen as with creating a new message, except the recipient is pre-selected and the subject is the subject of the previous message prexed with Re:. Room for improvement? There are three particular areas that can be improved signicantly: • Sent items • Replies • Group messages Sent items At the moment, we can't see sent items, and while in principle this could be added easily, the problem lies if a user deletes the message. We would need to add two columns to the database, one indicating that the recipient has deleted it from their inbox, and one indicating the sender has deleted it from their sent items, as we discussed earlier in the chapter. Download from Wow! eBook <www.wowebook.com> Chapter 7 [ 229 ] Replies Our replies are not linked together; they are all stored as standalone messages, which is something we could improve. Group messages At the moment, private messages are only between two users, but we may wish to extend this in the future to support any number of users. Summary In this chapter, we have taken extended statuses on our users' proles to support public messages between users. These public messages can use the comments system we have in place to form public conversations. We have also created a private messages area that allows users to communicate with one another in private. Next, we can look at further extending the statuses system to support more types of message. Download from Wow! eBook <www.wowebook.com> Download from Wow! eBook <www.wowebook.com> Statuses—Other Media With our status stream now supporting simple-text updates from the prole owner, and public messages from other users, it is time for us to integrate other types of media into these statuses. In this chapter, you will learn how to integrate other types of media in prole posts, including: • Images • Videos • Links The core information to our current statuses is held within the statuses table. We will keep this the same. However, depending on the type of status update, we may call upon other database tables to extend the information available to us. Since different status types will use different status tables, we should use a left join to connect the tables, so we can keep just a single query to look up the statuses. It also pulls in the extra information when it is required. Let's get started with extending our proles and the status stream! Why support other media types? The following are the potential uses of supporting other media types for Dino Space users: • Sharing videos of their pet dinosaurs • Sharing photographs with other users • Sharing relevant links with their contacts Download from Wow! eBook <www.wowebook.com> . $relationships->getByUser( $this->registry- >getObject('authenticate' )-& gt;getUser( )-& gt;getUserID() ); $this->registry->getObject('template' )-& gt;getPage( )- >addTag(. Message( $this->registry, $reply ); if( $message->getRecipient() == $this->registry- >getObject('authenticate' )-& gt;getUser( )-& gt;getUserID() ) { $this->registry->getObject('template' )-& gt;. ] >getObject('authenticate' )-& gt;getUser( )-& gt;getUserID() ) { if( $message->delete() ) { $url = $this->registry->getObject('url' )-& gt;buildURL( array(), 'messages', false ); $this->registry->redirectUser(