1

I'm hoping you can shed some light to my questions guys. What I need is basically the best practise of getting and assigning properties from database rows (instance getter). It is a pretty standart issue and I have know how it works in C#, but I'm unclear how to accomplish similar results in php and havent found any solution online which covers my needs.

So lets assume I have this simplified code:

Class User{
  private $Pdo;
  private $UserID;
  private $UserName;

  function GetUserName(){
    return $this->UserName;
    }

  function GetUserInfo(){
    // return user object with given user id, in this example just use "1"
    $Pdo = $this->Pdo;
    $Query = $Pdo->query('select * from User where UserID = 1');
    $Query->setFetchMode(PDO::FETCH_CLASS, "User", array($Pdo) ); // this is returning object
    $UserInfo = $Query->fetch();
    return $UserInfo;
    }

  }

Then when I wanted to get the user object I would call it like:

$User = new User($Pdo);
$UserInfo = $User->GetUserInfo();
echo $UserInfo->GetUserName();

This works, however I dont like to do it this way. One option would be to use static method so in the end I would end up with something like:

$UserInfo = User::GetUserInfo()

Which I suppose is called "Singleton" (edit: not a singleton:)) and is generally noted as bad practise.

My question is how it should look like? What I would like to have is this:

$UserInfo = new User($Pdo);
$UserInfo->GetUserInfo();
echo $UserInfo->GetUserName();

I know that in GetUserInfo method I can manually assign the values to current object ($this) such as:

function GetUserInfo(){
    // get data from db
    $this->UserName = "John"; // this value I will get from db
   }

However I would like to use FetchClass so I can get all the properties based on their names in one line and not assign them manually. I hope that you understand what my issue is :) I would love to hear your opinions of what is the best way of doing this.

Thank you very much for any input.

Enn
  • 2,030
  • 12
  • 20
  • `User::GetUserInfo()` isn't a singleton, it's a static method. singletons are simply objects that only allow themselves to be instantiated once. – Marc B Oct 09 '13 at 19:49
  • ok, didnt know that :) I saw similar examples and thought it was it. – Enn Oct 09 '13 at 19:54

1 Answers1

4

One step in the direction to a best pratice and good design would be to separate your domain models and the persistence layer.

So you are independent of the used database or could even replace the database with a webservice for example. Look at the Data Mapper pattern.

So your User model would only consist of the properties + getters/setters and methods that use these properties in some way (business logic).

class User
{
    protected $UserID;
    protected $UserName;

    public function getUserId()
    {
        return $this->UserID;
    }

    public function setUserId($userId)
    {
        $this->UserID = userId;
        return $this;
    }

    ...

}

Your mapper holds the database connection and is responsible for saving/fetching the User object.

class UserMapper
{
    protected $_pdo;

    public function __construct($pdo)
    {
        $this->_pdo = $pdo;
    }

    public function getUserById($id)
    {
        // TODO: better use prepared statements!
        $query = $this->_pdo->query("select * from User where UserID = ".id);
        $query->setFetchMode(PDO::FETCH_CLASS, "User");
        return $query->fetch();
    }

    public function save(User $user)
    {
        // insert/update query
    }

    ...

}

You can use it like:

$userMapper = new UserMapper($pdo);
$user = $userMapper->getUserById(1);

echo $user->getUserName();

$user->setUserName('Steve');
$userMapper->save($user);

There are other similar patterns like Table Gateway pattern. But I prefer the data mapper because of the independecy of the data source.

Look at the whole catalog from Martin Fowler: Catalog of Patterns of Enterprise Application Architecture

Another useful thread: What is the difference between the Data Mapper, Table Data Gateway (Gateway), Data Access Object (DAO) and Repository patterns?

Community
  • 1
  • 1
bitWorking
  • 11,824
  • 1
  • 30
  • 37
  • Hi, Thank you for the answer. I think I could give this one a shot. I was thinking of creating UserInfoProvider which would get me the object and you confirmed me that this should be a reasonable way to do this. – Enn Oct 09 '13 at 20:22
  • I have however one question - I read the article and it states that basically my User class will not even have any PDO (Sql) statements in it. So how would I go if I have a method which returns true/false if given user exists. I have to use PDO with SQL to check if user exists in database. However I have to work with this method in UserClass, this seems quite "over complicated" to me.. – Enn Oct 09 '13 at 20:29
  • Yes, the User class doesn't know anything about the persistence layer. The `getUserById` method should already return `null` if user not exists. Else you could make a method like `userExists($userName)` in the mapper which return true or false. But you're right, there are some pitfalls in using a data mapper or ORM approaches in general. Another option is to use a ready ORM system like [doctrine](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html) which have solved many of the problems already. – bitWorking Oct 09 '13 at 20:41
  • Will definitely check it out. Thank you very much for your time. Great Answer. – Enn Oct 09 '13 at 20:49
  • Hi, Thank you for the great answer. I think if I create getUserById(), getUserByName(), getUserNameByID(), ... So that will be too many methocs. Do you have any idea? – lyhong Feb 06 '15 at 03:15
  • @lyhong You could make one method `getUserByField($field, $value)`. And then use the field in the db query: `select * from User where ".$field." = ".$value`. (Better use prepared statement for the value and check if there's a column with the name of field to prevent sql injection) – bitWorking Feb 07 '15 at 11:15