Go Back   vb.org Archive > vBulletin Article Depository > Read An Article > vBulletin 3 Articles
FAQ Community Calendar Today's Posts Search

Reply
 
Thread Tools
Datamanagers: Objects as Data and Methods
Guest190829
Posts: n/a

 

Show Printable Version Email this Page Subscription
Guest190829 01-01-1970, 03:00 AM

If you haven't read this article on how to create custom data managers or perhaps you read it and don't see what the big deal is - please read further!

Why go through the complexity of a data manager when I can just manage my data with direct queries and procedural code?

vBulletin's data managing classes can look pretty complicated if you are unfamiliar with OO programming - but the benefits far surpass the few hurtles of adopting a more OO approach to your programming.

A Live Example

We'll start off with a project simulation. A client wants an application that keeps tracks of restaurant reviews. In order to achieve this, we need to set up a database tables that would look something like this:
Table: restaurant

| restaurant id | title | location | menuid | totalreviews

Table: review

| review id | restaurant id | rating | comments | userid

As you can, each review has a rating and user comments and links to a particular restaurant in the database.

A Procedural Approach

Tackling the project is a pretty standard task - the most obvious coding tasks being the insertion, updating, and deleting of restaurant reviews.

(Of course, there could be other aspects too this type of project, but the overall focus will be narrow only to supplement the article's message.)


Here is sample code for restaurant review insertion:

PHP Code:

# Clean variables
$vbulletin->input->clean_array_gpc('p', array('comments' => TYPE_STR,
                                               
'rating' => TYPE_UINT,
                                               
'restaurantid' => TYPE_UINT)
);

# Does the restaurant exist?
$restaurant $vbulletin->db->query_first("SELECT title FROM " TABLE_PREFIX "restaurant
                                             WHERE restaurant_id = " 
$vbulletin->GPC['restaurantid']);

if(!
$restaurant) {
   
// Submit error
}

# Is the rating valid? (1-5)
if($rating OR $rating 5) {
  
// Submit Error
}

# Error checking is done, we can add it to the database
$vbulletin->db->query_write("INSERT INTO " TABLE_PREFIX "review (userid, restaurant_id, rating, comments)
             VALUES (
                           " 
intval($vbulletin->userinfo['userid'] . ", "
                            
$vbulletin->GPC['restaurantid'] . ", "
                            
$vbulletin->GPC['rating'] . ", "           
                            
$vbulletin->db->escape_string($vbulletin->GPC['comments']) . ")"
);
// Print Redirect "You're review of $restaurant['title'] was submitted." 
We did basic error checking and then submitted it into the database. Now let's see some sample code for updating a restaurant review:

PHP Code:
#Clean variables
$vbulletin->input->clean_array_gpc('p', array('comments'      => TYPE_STR,
                                               
'rating'       => TYPE_UINT,
                                               
'restaurantid' => TYPE_UINT,
                                                
'reviewid'    => TYPE_UINT    
                                        
));
                                        
#Does the review exist?
$review $vbulletin->db->query_first("SELECT id FROM " TABLE_PREFIX ."review 
                                       WHERE reviewid = " 
$vbulletin->GPC['reviewid']);
                                    
if(!
$review) {
    
// submit error
}

#Is the new rating correct?
if($rating OR $rating 5) {
    
// Submit errror
}

#Update database
$vbulletin->db->query_write("UPDATE " TABLE_PREFIX ."review
                                SET comments = '" 
$vbulletin->db->escape_string($vbulletin->GPC['comments'])) . "'
                                    rating = " 
$vbulletin->GPC['rating'] . "
                                WHERE reviewid = " 
$vbulletin->GPC['reviewid']); 
The code between updating and inserting looks familiar, doesn't it? Your first thought should be that it looks a little too familiar. One of the quickest signs that your application is going down hill is seeing repeated logic in your code.

But what does this have too do with OO programming and objects? Can't we just code functions to prevent this code duplication?

The OO Mentality: Objects as Data and Methods

With procedural programming, data and behavior are two completely separate entities. You input data into a function and get specific data back. This may not be a problem at times but the data manager classes bring up a specific benefits when handling data.

Since objects are both data and methods, you can avoid messy situations with verifying data. The vBulletin Data Managers offer a nice clear and encapsulated way to check inputted variables. The class contains an array of valid fields which specify methods to verify the inputted data.

Our restaurant review would look something like this:

PHP Code:
var $validfields = array('reviewid'                =>             array(TYPE_UINT,    REQ_INCR,    VF_METHOD,    'verify_nonzero'),
                         
'restaurantid'            =>            array(TYPE_UINT,    REQ_YES,    VF_METHOD,    'verify_restaurant'),
                         
'comments'                    =>        array(TYPE_NOHTML,    REQ_YES),
                         
'rating'                =>            array(TYPE_UINT,    REQ_YES,    VF_METHOD,    'verify_rating')
                        ); 
See how the validfields key VF_METHOD maps to a specific method within the class that only performs one piece of logic. This not only offers a clear view on what method is handling what data, but it also encapsulates logic such that if you ever wanted to extend this data manager in the event of a future version with more extensive features or a simple change in feature, you can do it very easily.

Here would be some of the basic verification methods, all short and sweet:

PHP Code:
function verify_restaurant($restaurantid) {
        
$restaurant $this->registry->db->query_read("SELECT title FROM " TABLE_PREFIX ."restaurant WHERE restaurantid = " $restaurantid);
        if(!
$restaurant) {
            return 
false;
        }
        
        return 
true;
}

function 
verify_rating($rating) {
    return (
$rating OR $rating 5) ? false true;

With the data manager object, you neatly encapsulate the data and methods into a single entity. With a procedural approach, you'd have to pass the data quite messily along each function - or even worse, couple separate logic into a single function.

Also, with the object - you get increased portability. Adopting to the original insertion and update code with the data manager.

PHP Code:
$reviewdm =& datamanager_init('Review', &$vbulletin$errtype ERRTYPE_STANDARD$forcefile 'review');
$reviewdm->set('restaurantid'$vbulletin->GPC['restaurantid']);
$reviewdm->set('comments'$vbulletin->GPC['comments']);
$reviewdm->set('rating'$vbulletin->GPC['rating']);
$reviewdm->pre_save();
if (
count($reviewdm->errors) > 0)
{
    
$errors "<ul>";
   foreach(
$reviewdm->errors As $err)
   {
           
$errors .= '<li>' $err '</li>';
   }
   
$errors .= '</ul>';
  eval(
standard_error($errors));
}
else
{
    
$reviewdm $reviewdm->save();

Benefits:

  • It's not just your datamanager class data and methods you have at hand, but the base datamanager class you are extending from. This class hierarchy and code reuse you can not achieve with just procedural functions alone. You can simply alter some basic settings (the valid fields array, the table array, etc...etc...) and leave the bulk of the processing to the default class.
  • Easily portable: You can call the datamanager class from anywhere, the forums, the admin cp, and even any custom scripts you create powered by the vBulletin engine. (Calling global.php)
  • Keeps separate operations in there own methods and reduces code duplication.If you have to make an alteration to the business logic (say you want to restrict review comments to 500 characters) you only have to add a verify_comments() method to your class and alter the valid fields array.
  • Inheritance allows for easy extension of feature and entire sub-systems. If your client now wants the review system to accept not only restaurants but clubs and casinos, you can accomplish it easily by just extending from the default Review data manager class.
Conclusion:

The intention of this article was to shed to light the benefits of OO programming through a tool utilized and available to you in vBulletin. This article is focused on custom data managers, but the sky is the limit for creating OO applications. Good luck, and don't be afraid to take the dive into the powerful paradigm of object oriented programming.

Additional Reading:

Reply With Quote
  #2  
Old 09-04-2009, 06:34 PM
Come2Daddy Come2Daddy is offline
 
Join Date: May 2008
Posts: 128
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Thanks for sharing actually I'm not professional OOP, but I know about it as a philosophy I studied it & passed it in college but I don't have the skills to program in OOP style

so I'm not sure of how much have understood of this article, but I wonder why didn't you make the restaurantid auto increment

besides when we check for existence how could we know the restaurantid if we have thousands of restaurants

finally is it a must to use datamanger in inserting data into database via a form embedded in a powered by vbulletin page??? or we can just do procedurally ?
Reply With Quote
  #3  
Old 09-06-2009, 03:40 PM
Antivirus's Avatar
Antivirus Antivirus is offline
 
Join Date: Sep 2004
Location: Black Lagoon
Posts: 1,090
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Quote:
Originally Posted by Come2Daddy View Post
is it a must to use datamanger in inserting data into database via a form embedded in a powered by vbulletin page??? or we can just do procedurally ?
You can do it procedurally if you feel more comfortable doing it that way. It's really up to you as the coder. If a datamanager already exists however (for instance, in the case of users, posts, forums, etc...) then i would suggest ALWAYS using the datamanager supplied by vbulletin. The reason I suggest this, is because often the datamanager class will update other tables which the record in the primary table interacts with.

For instance: Say you want to write a query to create a reply by a specific user to a certain thread automatically. This could easily be done with a query, however you must also remember to do a slew of other things such as update the post count of the user making the reply, update the user's last reply dateline field, etc... The datamanager always handles
these things behind the scenes which you don't have to worry about - otherwise if you don't do all these things your forums can easily get out of whack. When creating a datamanager for yourself, the key is to code these issues into it to avoide complications later on.
Reply With Quote
  #4  
Old 09-09-2009, 06:43 AM
Come2Daddy Come2Daddy is offline
 
Join Date: May 2008
Posts: 128
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Thanks Antivirus

your answer added a lot to knowledge, now the picture is clearer
thanks a gain
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 11:35 PM.


Powered by vBulletin® Version 3.8.12 by vBS
Copyright ©2000 - 2024, vBulletin Solutions Inc.
X vBulletin 3.8.12 by vBS Debug Information
  • Page Generation 0.07517 seconds
  • Memory Usage 2,286KB
  • Queries Executed 17 (?)
More Information
Template Usage:
  • (1)SHOWTHREAD
  • (1)ad_footer_end
  • (1)ad_footer_start
  • (1)ad_header_end
  • (1)ad_header_logo
  • (1)ad_navbar_below
  • (1)ad_showthread_beforeqr
  • (5)bbcode_php
  • (1)bbcode_quote
  • (1)footer
  • (1)forumjump
  • (1)forumrules
  • (1)gobutton
  • (1)header
  • (1)headinclude
  • (1)modsystem_article
  • (1)navbar
  • (4)navbar_link
  • (120)option
  • (4)post_thanks_box
  • (4)post_thanks_button
  • (1)post_thanks_javascript
  • (1)post_thanks_navbar_search
  • (4)post_thanks_postbit_info
  • (3)postbit
  • (3)postbit_onlinestatus
  • (4)postbit_wrapper
  • (1)spacer_close
  • (1)spacer_open
  • (1)tagbit_wrapper 

Phrase Groups Available:
  • global
  • inlinemod
  • postbit
  • posting
  • reputationlevel
  • showthread
Included Files:
  • ./showthread.php
  • ./global.php
  • ./includes/init.php
  • ./includes/class_core.php
  • ./includes/config.php
  • ./includes/functions.php
  • ./includes/class_hook.php
  • ./includes/modsystem_functions.php
  • ./includes/functions_bigthree.php
  • ./includes/class_postbit.php
  • ./includes/class_bbcode.php
  • ./includes/functions_reputation.php
  • ./includes/functions_post_thanks.php 

Hooks Called:
  • init_startup
  • init_startup_session_setup_start
  • init_startup_session_setup_complete
  • cache_permissions
  • fetch_threadinfo_query
  • fetch_threadinfo
  • fetch_foruminfo
  • style_fetch
  • cache_templates
  • global_start
  • parse_templates
  • global_setup_complete
  • showthread_start
  • showthread_getinfo
  • forumjump
  • showthread_post_start
  • showthread_query_postids
  • showthread_query
  • bbcode_fetch_tags
  • bbcode_create
  • showthread_postbit_create
  • postbit_factory
  • postbit_display_start
  • post_thanks_function_post_thanks_off_start
  • post_thanks_function_post_thanks_off_end
  • post_thanks_function_fetch_thanks_start
  • post_thanks_function_fetch_thanks_end
  • post_thanks_function_thanked_already_start
  • post_thanks_function_thanked_already_end
  • fetch_musername
  • bbcode_parse_start
  • bbcode_parse_complete_precache
  • bbcode_parse_complete
  • postbit_display_complete
  • post_thanks_function_can_thank_this_post_start
  • postbit_imicons
  • tag_fetchbit_complete
  • forumrules
  • navbits
  • navbits_complete
  • showthread_complete