tags:

views:

122

answers:

5

Hello I am just learning more about using classes in PHP. I know the code below is crap but I need help.

Can someone just let me know if I am going in the right direction.

My goal is to have this class included into a user profile page, when a new profile object is created, I would like for it to retrieve all the profile data from mysql, then I would like to be able to display any item on the page by just using something like this

$profile = New Profile;
echo $profile->user_name;

Here is my code so far, please tell me what is wrong so far or if I am going in the right direction?

Also instead of using echo $profile->user_name; for the 50+ profile mysql fileds, sometimes I need to do stuff with the data, for example the join date and birthdate have other code that must run to convert them, also if a record is empty then I would like to show an alternative value, so with that knowlege, should I be using methods? Like 50+ different methods?

<?PHP
//Profile.class.php file

class Profile
{
    //set some profile variables
    public $userid;
    public $pic_url;
    public $location_lat;
    public $location_long;
    public $user_name;
    public $f_name;
    public $l_name;
    public $country;
    public $usa_state;
    public $other_state;
    public $zip_code;
    public $city;
    public $gender;
    public $birth_date;
    public $date_create;
    public $date_last_visit;
    public $user_role;
    public $photo_url;
    public $user_status;
    public $friend_count;
    public $comment_count;
    public $forum_post_count;
    public $referral_count;
    public $referral_count_total;
    public $setting_public_profile;
    public $setting_online;
    public $profile_purpose;
    public $profile_height;
    public $profile_body_type;
    public $profile_ethnicity;
    public $profile_occupation;
    public $profile_marital_status;
    public $profile_sex_orientation;
    public $profile_home_town;
    public $profile_religion;
    public $profile_smoker;
    public $profile_drinker;
    public $profile_kids;
    public $profile_education;
    public $profile_income;
    public $profile_headline;
    public $profile_about_me;
    public $profile_like_to_meet;
    public $profile_interest;
    public $profile_music;
    public $profile_television;
    public $profile_books;
    public $profile_heroes;
    public $profile_here_for;
    public $profile_counter;

    function __construct($session)
    {
    // coming soon
    }

    //get profile data
    function getProfile_info(){
     $sql = "SELECT user_name,f_name,l_name,country,usa_state,other_state,zip_code,city,gender,birth_date,date_created,date_last_visit,  
     user_role,photo_url,user_status,friend_count,comment_count,forum_post_count,referral_count,referral_count_total,
     setting_public_profile,setting_online,profile_purpose,profile_height,profile_body_type,profile_ethnicity,
     profile_occupation,profile_marital_status,profile_sex_orientation,profile_home_town,profile_religion,
     profile_smoker,profile_drinker,profile_kids,profile_education,profile_income,profile_headline,profile_about_me,
     profile_like_to_meet,profile_interest,profile_music,profile_television,profile_books,profile_heroes,profile_here_for,profile_counter
     FROM users WHERE user_id=$profileid AND user_role > 0";
     $result_profile = Database::executequery($sql);

     if ($profile = mysql_fetch_assoc($result_profile)) {
      //result is found so set some variables
      $this->user_name = $profile['user_name'];
      $this->f_name = $profile['f_name'];
      $this->l_name = $profile['l_name'];
      $this->country = $profile['country'];
      $this->usa_state = $profile['usa_state'];
      $this->other_state = $profile['other_state'];
      $this->zip_code = $profile['zip_code'];
      $this->city = $profile['city'];
      $this->gender = $profile['gender'];
      $this->birth_date = $profile['birth_date'];
      $this->date_created = $profile['date_created'];
      $this->date_last_visit = $profile['date_last_visit'];
      $this->user_role = $profile['user_role'];
      $this->photo_url = $profile['photo_url'];
      $this->user_status = $profile['user_status'];
      $this->friend_count = $profile['friend_count'];
      $this->comment_count = $profile['comment_count'];
      $this->forum_post_count = $profile['forum_post_count'];
      $this->referral_count = $profile['referral_count'];
      $this->referral_count_total = $profile['referral_count_total'];
      $this->setting_public_profile = $profile['setting_public_profile'];
      $this->setting_online = $profile['setting_online'];
      $this->profile_purpose = $profile['profile_purpose'];
      $this->profile_height = $profile['profile_height'];
      $this->profile_body_type = $profile['profile_body_type'];
      $this->profile_ethnicity = $profile['profile_ethnicity'];
      $this->profile_occupation = $profile['profile_occupation'];
      $this->profile_marital_status = $profile['profile_marital_status'];
      $this->profile_sex_orientation = $profile['profile_sex_orientation'];
      $this->profile_home_town = $profile['profile_home_town'];
      $this->profile_religion = $profile['profile_religion'];
      $this->profile_smoker = $profile['profile_smoker'];
      $this->profile_drinker = $profile['profile_drinker'];
      $this->profile_kids = $profile['profile_kids'];
      $this->profile_education = $profile['profile_education'];
      $this->profile_income = $profile['profile_income'];
      $this->profile_headline = $profile['profile_headline'];
      $this->profile_about_me = $profile['profile_about_me'];
      $this->profile_like_to_meet = $profile['profile_like_to_meet'];
      $this->profile_interest = $profile['profile_interest'];
      $this->profile_music = $profile['profile_music'];
      $this->profile_television = $profile['profile_television'];
      $this->profile_books = $profile['profile_books'];
      $this->profile_heroes = $profile['profile_heroes'];
      $this->profile_here_for = $profile['profile_here_for'];
      $this->profile_counter = $profile['profile_counter'];
     }
    //this part is not done either...........
    return $this->pic_url;
    }
}
+1  A: 

Don't use a whole bunch of public variables. At worst, make it one variable, such as $profile. Then all the fields are $profile['body_type'] or whatever.

wallyk
Using a property per field has an advantage : auto-completion in any decent IDE (your solution does not have that advantage -- at least, unless you define the right doc-blocks)
Pascal MARTIN
What do you think about switching to use a method for each item, so I can run other code on each output such as converting numbers on number variables and on any variable that comes back from the DB as being blank, I could make the method cshow alternative text?
jasondavis
+3  A: 

You should look into making some kind of class to abstract this all, so that your "Profile" could extend it, and all that functionality you've written would already be in place.

You might be interested in a readymade solution - these are called object relational mappers.

You should check out PHP ActiveRecord, which should easily allow you to do something like this without writing ORM code yourself.

Other similar libraries include Doctrine and Outlet.

Veeti
+4  A: 

You might want to take a look at PHP's magic methods which allow you to create a small number of methods (typically "get" and "set" methods), which you can then use to return/set a large number of private/protected variables very easily. You could then have eg the following code (abstract but hopefully you'll get the idea):

class Profile
{
  private $_profile;

  // $_profile is set somewhere else, as per your original code

  public function __get($name)
  {
    if (array_key_exists($name, $this->_profile)) {
      return $this->_profile[$name];
    }
  }

  public function __set($name, $value)
  {
    // you would normally do some sanity checking here too
    // to make sure you're not just setting random variables

    $this->_profile[$name] = $value;
  }
}

As others have suggested as well, maybe looking into something like an ORM or similar (Doctrine, ActiveRecord etc) might be a worthwhile exercise, where all the above is done for you :-)

Edit: I should probably have mentioned how you'd access the properties after you implement the above (for completeness!)

$profile = new Profile;

// setting
$profile->user_name = "JoeBloggs";

// retrieving
echo $profile->user_name;

and these will use the magic methods defined above.

richsage
+1 for magic, and using an ORM (I personnaly kind of like Doctrine) instead of re-inventing the wheel -- note that magic methods will also have to inconvenient of no auto-completion in IDE (unless, too, you use the right docblocks ;; from what I remember, Doctrine generates those, btw)
Pascal MARTIN
there is around 50 different items for each profile page to show, a lot of these items need to be modified before showing, for example some of the dates are converted and I would like to show an alternative value if the result is empty, I beleive I could add all this functionality into your example but if I didn't use get/set should I build a class with like 50 different methods? Maybe the construct method can retrieve the data from DB then the other methods will show the results
jasondavis
@jason you can either build it into a single object as per my example (array etc which I presume you'd get from the database as a single row), or you can have 50 individual class member variables. You could build your default values into the methods above dependant on the $name asked for, or you could create get*() methods for each item.
richsage
A: 

Normally, a class would be created to abstract the things you can do to an object (messages you can send). The way you created it is more like a dictionary: a one-to-one mapping of the PHP syntaxis to the database fields. There's not much added value in that: you insert one extra layer of indirection without having a clear benefit.

Rather, the class would have to contain what's called a 'state', containing e.g. an id field of a certain table, and some methods (some...) to e.g. "addressString()", "marriedTo()", ....

If you worry about performance, you can cache the fields of the table, which is a totally different concern and should be implemented by another class that can be aggregated (a Cache class or whatsoever).

The main OO violation I see in this design is the violation of the "Tell, don't ask" principle.

xtofl
What do you think about me making like 50 different methods that process the items I need to show, for example if the item from the DB is a date, then the method for showing that date would run other code to format the way it shows and then prints it to screen, also each of these methods would check to see if the value is empty, if it is then the class method would make it show an alternative text. Is that improper?
jasondavis
I would rather add a method to render the 'showingHtml' code, in an attempt to not expose the content of the object, but rather ask it how it would like to be displayed as e.g. a html form. This idea has been coined as the Visual Proxy pattern in one of Holub's articles. The article has a very neat explanation of some basic OO concepts, too (See http://www.javaworld.com/javaworld/jw-09-1999/jw-09-toolbox.html)
xtofl
+1  A: 

This looks like a Data Class to me, which Martin Fowler calls a code smell in his book Refactoring.

Data classes are like children. They are okay as a starting point, but to participate as a grownup object, they need to take some responsibility.

He points out that, as is the case here,

In the early stages these classes may have public fields. If so, you should immediately Encapsulate Field before anyone notices.

If you turn your many fields into one or several several associative arrays, then Fowler's advice is

check to see whether they are properly encapsulated and apply Encapsulate Collection if they aren't. Use Remove Setting Method on any field that should not be changed.

Later on, when you have your Profile class has been endowed with behaviors, and other classes (its clients) use those behaviors, it may make sense to move some of those behaviors (and any associated data) to the client classes using Move Method.

If you can't move a whole method, use Extract Method to create a method that can be moved. After a while, you can start using Hide Method on the getters and setters.

Ewan Todd
Of course, this advice is fairly generic. One thing I like about your class is that you pass in `$session` instead of relying upon some global data. This is called dependency injection, and it makes it possible to give your class dummy data in a unit test.
Ewan Todd