I have a table called "User" that holds user info. I'll call my user class and create a user object so that I can grab whatever info is needed for that user.
I have been using the below classes and hybrids of them for my sites but have been never really happy with them mainly because I'm unsure how other developers handle this situation and if there is a better solution. Below are a few methods I have been using, I'm curious to see how other developers are doing.
Idea # 1
class User
{
//public user
public function __construct()
{
//get user - queries table and returns all fields in array
}
//get name function - references user array and returns name
//set name function - sets new name in array
//commit function - commits array to db (saves changes)
}
Idea # 2
class User
{
//user id
public function __construct(user id)
{
//set user id
}
//get name function - calls db directly and returns name
//set name function - calls db directly and sets name
//commit function - commits array to db saves changes
}
Idea #1 seems to be the most efficient, or least amount of DB calls but a little more complex and less straightforward than Idea #2.
I like idea #2 better but I'm afraid of it's scalability because each function makes a call to the DB.
Thoughts
I would recommend for you to learn about DataMapper pattern. The basic idea goes like this :
Lets say (for the sake of example ) that you have an MVC structure for application that deals with books.
It would make sense to have a model Library which is responsible with domain logic of managing different books.
The model deals with unknown number of Book instances ( many books in a library ). Each book :
knows everything about itself ( authors , publishing date , language .. etc.)
has no idea where it is stored or where the data come from
can be related to a table in Database , but contains information from multiple tables
And then you have an instance of BookMapper class, which :
model receives in the constructor ( implementing predefined interface )
knows how to ( and where ) store the Book objects , and how to read data into them
can be switched to a different object, if storage medium changes
if it works with DB, then it in constructor has already requested a DB object ( like PDO )
has methods store( Book $book ) and retrieve( Book $book ) for saving book's data , or getting new info from storage
This is how i would do it ..
What about something like:
class Db
{
function __construct()
{
$this->engine = DB_ENGINE;
$this->dbname = DB_NAME;
$this->host = DB_HOST;
$this->username = DB_USERNAME;
$this->password = DB_PASSWORD;
$this->connect();
}
function connect()
{
$this->db = new PDO($this->engine.':host='.$this->host.';dbname='.$this->dbname, $this->username, $this->password);
}
}
class Table extends Db
{
protected $from = null;
function __construct()
{
parent::__construct();
}
function select($columns, $where, $order, $offset, $limit)
{
}
function update($where, $data)
{
}
function delete($where)
{
}
etc...
}
class User extends Table
{
function __construct()
{
parent::__construct();
$this->from = 'blog';
}
function get_user()
{
$this->select(params);
}
function get_user_count()
{
}
etc...
}
This way you can easily use it to get other info as well just be creating a new class with it's functions to retrieve / delete / etc the info.
Firstly the user object is meant to hold user data, so i would suggest method #1, method #2 is more of a amodel object that send's commands to fetch data.
Now, you can automatically map user rows to an object in 1 single query, for example:
class User
{
//Predefine Here
public $id;
public $username;
public $password;
public $email;
public $hash;
public function profileLink()
{
return sprintf('%s',$this->id,$this->username);
}
}
//Fetch the results
$result = $sth->fetchAll(PDO::FETCH_CLASS, "User");
$userObjects = array();
foreach($result as $user)
{
$userObjects[] = $user;
}
//Now you can use like so:
echo $userObjects[2]->profileLink();
so my other answer here : PDO PHP Fetch Class
I think that if you are going to implement your own User class, then it should look something similar to the following:
class User {
private $UserID;
private $Username;
private $AvatarImg;
// ... First Name, Last Name, ALL other user information that you store in the DB.
function __construct( $uid ) {
// Populate all private members from the DB for the given user id.
}
function update( $assocArrayOfValues ) {
// Commit these values to the Db and Update the private members.
}
// All Associated get functions ( getName, getUID, getUsername etc )
// Any other specialty functions you may want, e.g...
function getAvatar() {
return "<img src = '" . $this->AvatarImg . "'/>";
}
}
What you are trying to archive is the functionally of an ORM (Object-Relational-Mapper). It may be beneficial to use one and not do it yourself.
If you want to do it on your own, I would go for lazy-loading. This is a bit in between your two ideas. In PHP it looks something like this:
class User
{
private $id; // depends on your application, could also be a string
private $dirty;
private $loaded;
private $properties;
public function __construct($user_id)
{
$this->id = $user_id;
}
public function __destruct()
{
if ($this->dirty) {
// commit to DB
}
}
public function __get($name)
{
if (!$loaded)
{
$this->loadFromDb();
}
// error-handling if the key does not exist is missing here!
return $this->properties[$name];
}
public function __set($name, $value)
{
// May be required to load the data here...
// error-handling if the key does not exist is missing here!
$properties[$name] = $value;
$this->dirty = true;
}
private function loadFromDb()
{
// query data from db and store it in properties
}
}
The advantage of this design is, that if you construct objects, which ultimately you don't need, nothing has touched the database yet. Also note the commit done during deconstruction.
If you load collections sometimes it may be useful to have a function load a bunch of rows from the DB and pass the rows as argument to a constructor when creating the objects. This would require only one query instead of possibly hundreds if you would have constructed each object by itself.
As a further enhancement you may provide a User::reset() function, which throws away all the changes made.
I would suggest you to use a PHP-Framework like Yii.
http://www.yiiframework.com/
It has nice Features to interact between Classes and your Database.
You can also get some inspiration there if you really want to do this on your own.
Related
I am novice in OOP programming in php and trying to understand and implement the dependency injection feature in my MVC project. In the following I am explaining a super simple example of the feature where I am struggling applying the dependency injection. The actual application is lot more complex than this, however, this should be enough to demonstrate the problem I am having.
I have created a Model called “user” that is responsible for managing a single user. Data handled by the class (data about a user) is also saved in the database table. The “user” class has method to load from and save/update the data to the database table. The user class can be initiated with data loaded from the database (by using user id) or load from the array supplied to the constructor.
The project deals with multiple users at a time. So, I have created a container class called “users”. This class has an array of “user” objects. However, this class also have method to load data for multiple user objects from the database (based on criteria such as all paid users), then create the object array with the data. The number of object is created is depends on the number of users returned from the database.
The following is a sample code for the classes
class user
{
private $data;
function __construct ($arData=””)
{
$this->dbTable ="user";
if(!is_array($ar))
{
if($ar!="")
{
$ar = $this->getDataFromDB($ar);
}
else
{
$ar = array();
}
}
$this->data = $ar;
}
function getDataFromDB($id_user){ … data base implementation … }
....
Other methods
....
}
class users // the container class
{
private $objUsers;
function __ construct(){
$this->objUsers = array();
}
function loadUsers($type){
$userDataArray = $this->getUsersFromDatabase($type);
foreach($useDataArray as $userData){
$this->objUsers[] = new user($userData);
}
}
function getUsersFromDatabase($userType) { …… database …… }
…… other methods …..
}
My concern is the container class (container may not be the right word to say). I want to know the best practice to create this type of container class and what is the recommend for this. In addition, this is clearly evident that this container class is tightly coupled with “user” class and cannot be tested separately. How can I implement the dependency injection for a class like this?
As I said, I don't think this is a good fit for dependency injection. And I wouldn't set it up that way just for the sake of saying it uses dependency injection.
The main reason it's not a good fit, is that a User is always a User. So you always have a concrete contract between the wrapper, Users, and the User. You can count on User having certain methods. And you don't have some weird 3rd class that your adding into these collections, it's just a collection of a known and well defined object.
That said, I would go with a more factory style wrapper, Where the User is the simpler of the 2 classes. ( note, I didn't test any of this, so just look at it like psudo code )
class users {
public function createUser( array $data = []){
if( $data['id'] ){
$User = $this->getUser( $data['id'] );
if( $User )
return $User;
}
//depending what you want you could search on other things
//like the email, (unique) and return the user.
//you could make this as complex, or as simple as you want
//it could simply create a new user, or check for an existing one first.
return new User($data); //dependency
}
public function getUser( $id ){
$stmt = $this->DB->prepare( "SELECT * FROM users WHERE id=:id" );
$stmt->FetchMode(PDO::FETCH_CLASS, 'User');
return $stmt->fetch(); //fetch right into the class
}
public function saveUser( User $User ){
//I just added this to show how you can type hint the class
// so that it only accepts Objects of the type User
}
}
class user{
protected $id;
protected $username;
protected $email;
public function __construct(array $data = []){
foreach( $data as $field=>$value){
//this could be done better, with error checking etc.
//but I just wanted to show how you can use the setters
//dynamically when constructing with an array
//this is useful because we are not hard coding the schema of User in any files
//-note- PHP method calls are case insensitive.
$this->set{$field} = $value;
}
}
public function setId( $id ){ $this->id = $id; }
public function getId(){ return $this->id; }
public function setUsername( $username ){ $this->username = $username; }
public function getUsername(){ $this->username; }
public function setEmail( $email ){ $this->email = $email; }
public function getEmail(){ return $this->email; }
}
Then you can worry about dependency injection for things like the Database. This could be represented by having the users constructor accept a PDO or Database object. Like this
class Users{
protected $DB;
public function __construct( $DB ){
$this->DB = $DB;
}
}
The Users class doesn't care about the DB credentials, or even the particular DB driver your using. To some extent it does have some coupling with the driver based on the SQL syntax, which may be specific to a particular database. If we wanted to make this a "truer" form of dependency injection we should use an ORM like Doctrine, or some kind of Query builder ( instead of PDO itself ). Then we would have another layer of abstraction between our code and the database.
If you need user to have access to users and they cant be separated extend the class.
class users {
}
class user extends users {
}
Child user can then access the parent users properties.
I've been programming in PHP for many years, however only recently started programming with classes. I have the following - basic - user class as follows:
<?php
/* The class for constructing any user's information
*/
class User {
protected $userId, $email, $userGroup;
protected function getEmail() {
return $this->email;
}
protected function getUserId() {
return $this->userId;
}
protected function getUserGroup() {
return $this->userId;
}
public function __construct($userId='') {
if($userId) {
$select = mysql_query("SELECT userId, email, user_group FROM user WHERE userId = '$userId'");
while($user==mysql_fetch_array($select)) {
$this->email = $user[email];
$this->userId = $userId;
$this->userGroup = $user[user_group];
}
}
}
}?>
So I understand I can do the following
<?php
$user = new User($userId);
echo $user->getEmail();
?>
To display the user's email address for a given userId. What I'd like to know is, what would be the best way - using OOP - to display, say, 40 user's emails. Obviously creating 40 user objects would be silly as that's 40 SQL queries. Would you simply make a "users" class that was used for returning an array of multiple users, after doing an SQL given various parameters?
Ie
<?php
$getUsers = new Users('Tom');
// create 'Users' object where name is 'Tom'
print_r($users);
// prints the returned array of users?
?>
Thanks for your help. Hopefully this is clear.
I'd do it something like this (using another class):
class UserRepository {
public function getByName($name) {
$result = mysql_query("SELECT userId, email, user_group FROM user WHERE name = '$name'");
$users = [];
while ($row = mysql_fetch_assoc($result)) {
$user = new User;
$user->email = $row['email'];
$user->userId = $row['userId'];
$user->userGroup = $row['user_group'];
$users[] = $user;
}
return $users;
}
}
Addition:
The following example gives a good idea on how you can make the classes more testable and easy to modify in the future should they need to be:
UserRepositoryInterface
interface UserRepositoryInterface {
public function getByName($name);
public function getByUserId($id);
}
MySqliUserRepository
class MySqliUserRepository implements UserRepositoryInterface {
public function getByName($name) {
// Get by name using mysqli methods here
}
public function getByUserId($id) {
// Get by user id using mysqli methods here
}
}
PDOUserRepository
class PDOUserRepository implements UserRepositoryInterface {
public function getByName($name) {
// Get by name using PDO methods here
}
public function getByUserId($id) {
// Get by user id using PDO methods here
}
}
Usage
class Foo {
protected $userRepository;
public function __construct(UserRepositoryInterface $userRepository) {
$this->userRepository = $userRepository;
}
public function bar() {
$user = $this->userRepository->getByUserId(10);
}
}
Regarding use of mysql_
It may not be exactly how you do it but it'll give you an idea. Also mysql_ is depreciated so its best to use mysqli_ or PDO (my personal recommendation). PDO is also much more OOP friendly.
PDO: http://php.net/manual/en/book.pdo.php
mysqli_: http://php.net/manual/en/book.mysqli.php
Update:
Your individual user class would simply contain information relating to the user. The user class shouldn't contain any way to retrieve a user, that is the job of the repository. So if you want to retrieve 1 user, instead of doing in the User __construct as you currently do, add a method to the UserRepository that looks something like this:
public function getByUserId($id) {
// Select user from db, check only 1 exists, make user object, return.
}
I try to separate my data objects from the DB stuff. In your case, I'd make the following arrangements:
An instance of the User class represents an individual user, either in DB or not. The constructor does not retrieve anything from DB, it just populates class properties.
For users not in DB (e.g., a newly created user) the userId property is NULL (not '').
Methods that do DB stuff expect a database interface (or at least an object) as argument:
public function save(PDO $pdo){
}
There're static methods to fetch stuff from DB where a class instance does not make sense yet; they return either a User instance or a User collection:
public static function fetchById(PDO $pdo, $id){
}
public static function fetchAll(PDO $pdo){
}
When it makes sense, I write a private method to share common code:
private static function fetch(PDO $pdo, array $filter=array()){
$sql = 'SELECT id, email, group
FROM user' . PHP_EOL;
$params = array();
if( isset($filter['id']) ){
$sql .= 'WHERE id=:id';
$params['id'] = $filter['id'];
}
//...
}
public static function fetchById(PDO $pdo, $id){
$data = self::fetch($pdo, array('id' => $id));
if( empty($data) ){
return NULL;
}else{
reset($data);
return curren($data);
}
}
public static function fetchAll(PDO $pdo){
return self::fetch($pdo);
}
The User collection I've mentioned can as simple as an array of User instances, or as elaborate as your own generics implementation.
This way, a typical script looks like this:
// Fetch my details
$me = User::fetchById(1);
// Create a new user
$you = new User(NULL, 'Joe', 'Guests');
$you->save($pdo);
$message = sprintf('User created with ID=%d', $you->userId);
Instead of using the construct to retrieve a user, you could use methods to insert/retrieve users instead.
You can create methods to insert new users, update a particular user, retrieve one particular user or retrieve all (with conditions) in an array of users' objects, etc
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.
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?
So, lets say I have a record:
$record = new Record();
and lets say I assign some data to that record:
$record->setName("SomeBobJoePerson");
How do I get that into the database. Do I.....
A) Have the module do it.
class Record{
public function __construct(DatabaseConnection $database)
{
$this->database = $database;
}
public function setName($name)
{
$this->database->query("query stuff here");
$this->name = $name;
}
}
B) Run through the modules at the end of the script
class Record{
private $changed = false;
public function __construct(array $data=array())
{
$this->data = $data;
}
public function setName($name)
{
$this->data['name'] = $name;
$this->changed = true;
}
public function isChanged()
{
return $this->changed;
}
public function toArray()
{
return $this->array;
}
}
class Updater
{
public function update(array $records)
{
foreach($records as $record)
{
if($record->isChanged())
{
$this->updateRecord($record->toArray());
}
}
}
public function updateRecord(){ // updates stuff
}
}
A question you could ask yourslef is whether you want to reinvent the wheel or not. ORM layers like Propel or Doctrine already implement object to (R)DBMS mapping, so you might look at their implementation details.
Propel will use your second approach, they even keep flags on a field level to create just one update statement (which will keep database interaction at a minimum). You'll learn a lot if you study their source (or better yet, stop wasting your time and use their implementation - you won't regret it :p).
It depends on how you plan to implement... Doing all the writes at a single point (at the end of a request) is nice because it allows you to optimize your operations by consolidating queries where possible. But to do that you have to create something similar to a UnitOfWork to keep track of whats a delete/update/insert which can open a whole other can of worms.
On the other hand if you do it directly when you call the persistence method on the entity then you dont have to worry about that quite as much.
Both approaches though mean you have to have some way to make sure you always have the current data in your object but the work required to implementation that varies in complexity with he approach you choose.
Example A updates the database whenever setName is called. This function looks like a simple write accessor but it performs expensive actions when called (connecting to the database, executing a query, etc). These unintended site-effects make Example B far more appealing.
As a further example: Later on you might need a Validator class that examines a Record and ensures that the Record is in a valid state. But in order to examine the Record you must define it first by setting a name - so the Record will be persisted before you can validate it's state. Defining object state is not the same as persisting object state.
A data model approach might work better instead of a record-based approach. For instance:
class Model {
protected $_props= array();
public $changed= false;
static public $models= array();
function __set($name, $value) {
$this->changed= true;
$this->_props[$name]= $value;
}
function __construct() {
Model::$models[]= $this;
}
public function save() {
// Execute database query for saving the current Model
}
static public function update() {
foreach (Model::$models as $model) {
if ($model->changed) {
$model->save();
}
}
}
}
A model-based solution really shines when it comes to creating different Model types. For instance:
class Person extends Model {
public function save() {
// Execute person-specific write operations
}
}
class Doctor extends Person {
public function save() {
// Execute all Person write operations
parent::save();
// Save the extra bits that belong to a doctor
}
}
$person1= new Person();
$person->firstname= 'Jon';
$person->lastname= 'Skeet';
$doctor1= new Doctor();
$doctor1->firstname= 'House';
$doctor1->lastname= 'MD';
// Save all modified models
Model::update();
Though I rarely find use for these kind of mass update mechanisms. Write conditions are usually more specific.
ive got a user class where i can get the name, date of birth etc of the user... (below)
class user {
private $id;
private $name;
private $dob;
private address;
function __construct($id) {
$this->id = $id
}
}
i was just wondering what the best practice to get all users. do i create a function to get an object of this class for each user found from the database? :s
From a purely OO perspective, the User shouldn't have knowledge of databases etc.
My first thoughts would be a UserFactory, which will talk to the database and know how to build User objects from SQL results. You may want to specialise this to have a SQLUserFactory, an XMLUserFactory etc.
It's worth reading about Factory patterns. Factories look after the creation of objects. In this scenario, you may want to later distinguish between different types of User objects. In this scenario it would be the Factory's responsibility to decide what sort of object to create, not the User's.
This looks like an attempt at Active Record. In php there are a few ORM implementations that include Active Record. I suggest looking into that.
Otherwise look into at PDO and binding query results to objects. You might be able to get something working that way.
Do you mean which class should have the responsibility for getting Users from the DB?
The User class seems wrong, why would an indivudual user "know" about queries to obtain all (or some) users.
You could have a UserHome or UserKeeper class. and in there have methods which return result sets of user.
Getting users from a database isn't an OOP question, it's a database question, and typically an SQL question. Unless I don't get what you mean?
Object models in this case are somewhat artificial because putting a load() or get() method on the user class doesn't make a lot of sense because you don't want to get 100 users with 100 separate database roundtrips/selects. It's an example of "leaky abstractions". Implementation matters.
So you're going to need to write a function to run a query, return a bunch of rows and turn them into user objects.
Or use an ActiveRecord-like abstraction (eg that used in CodeIgniter or Kohana) to a set of records by passing in a criteria or a set of records.
Assuming your users are stored in a MySQL database, I would create the following static method in Users. Well, I would probably use an ORM, like Doctrine instead, but...
static function queryAll() {
$query = "SELECT id,name,dob,address FROM user";
if ($result = $mysqli->query($query)) {
$all = array();
while ($obj = $result->fetch_object()) {
$all[$obj->id] = $obj;
}
$result->close();
return $all;
}
return array();
}
In my point of view Database interaction should be separate and put in model as of in zend framework and controlled from controller where you should make of object of model class and call fetch all function.
Is this is the right approach.
class User
{
public $id;
public $username;
public $password;
public function __construct()
{
$this->username = "";
$this->password = "";
}
}
separate database interactions to an interface
interface UserStore
{
public function Create(User $user) : User;
//public function GetById(string $id) : ?User;
public function getByUserName(string $userName) : ?User;
}
implement the interface.
class MySqlUserStore implements UserStore
{
public $db;
public function __construct($db)
{
$this->db = $db;
}
public function Create( User $user) : User
{
$query = "INSERT INTO users (username, password) VALUES (?, ?)";
$user->id = $this->db->insert($query, array($user->username, $user->password));
return $user;
}
public function getByUserName(string $userName) : ?User
{
$query = "SELECT * from users where username = ?";
$result = $this->db->select($query, array($userName));
if(count($result) > 0) {
$user = new User();
$user->id = $result[0]['id'];
$user->username = $result[0]['username'];
$user->password = $result[0]['password'];
return $user;
}
return null;
}
}
Use the user store
$userStore = new MySqlUserStore($this->db);
$user = $userStore->getByUserName($username);