I'm trying to figure out how to properly work this out. I don't know if I'm applying things correctly. I think it's a good thing to separate the User object, from the database operations, meaning that User class shouldn't know how to operate with the DB. Thats why I created another class UserModel (I'm not sure of how to name this class) which will be the one handling the db queries and returning their results. Before, I was selecting, inserting, updating and deleting from the User class, but I felt like that responsability didn't belong to that class. Why a User should return a set of Users? That didn't make sense to me.
I also got doubts when using the database, as I don't know how to properly use PDO.
(In this example I've only implemented the Insert query, the other methods are implemented the same way.)
Let's get started.
User.php
class User {
private $id;
private $name;
private $email;
private $username;
private $password;
//Getters & Setters
}
UserModel.php (Should this be called UserModel?)
class UserModel {
private $db;
private $pdo;
public function __construct()
{
$db = new Database;
$pdo = $db->getPDO();
}
public function createUser($user)
{
$sql = 'INSERT INTO users (`name`,`email`,`username`,`password`) VALUES(:name, :email, :username, :password)';
$pdo->prepare($sql);
$pdo->bindValue(':name', $user->getName(), PDO::PARAM_STR);
$pdo->bindValue(':email', $user->getEmail(), PDO::PARAM_STR);
$pdo->bindValue(':username', $user->getUsername(), PDO::PARAM_STR);
$pdo->bindValue(':password', $user->getPassword(), PDO::PARAM_STR);
return $pdo->execute();
//return true if inserted, return false if not
}
public function editUser($user)
{
}
public function deleteUser($uid)
{
}
public function getUser($uid)
{
}
public function getAllUsers()
{
}
}
Database.php
class Database {
private $pdo;
public function __construct()
{
$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
}
public function getPdo() {
return $this->pdo;
}
}
users.php
$usermodel = new UserModel;
$user = new User;
$user->setName('John');
$user->setEmail('john#john.com');
$user->setUsername('john');
$user->setPassword('1234');
$usermodel->createUser($user);
Looks good to me as a custom based user model solution. These work awesome for small projects since they're so lightweight and you're able to customize each to your taste.
As you scale up you'll notice this has to be done/customized for each database table and if you have joins... things may get hairy to say the least.
I would recommend you take a look at the ORMs used within major php frameworks: zend, laravel, cake among others.
The ORM essentially does auto-mapping based on table name/primary key. Assuming you're ok with SOME 'magic' and losing full control over data in and data out you will have the same ability you've created for the user object in any other table you add by setting the two defaults I mentioned.
On the downside is the performance hit you'll experience. Here's some stats on the line count/file count of the frameworks I mentioned:
https://stackoverflow.com/questions/28923085/should-i-use-laravel-framework-if-i-use-wordpress/28923187#28923187
Related
Today i tried to convert my functions to PHP Class.
I tried with some basic steps.
<?php
class DataBase {
private $host;
private $user;
private $password;
private $db;
private $mysqli;
function __construct() {
$this->host = "localhost";
$this->user = "root";
$this->password = "";
$this->db = "my_database";
$this->mysqli = new mysqli($this->host, $this->user, $this->password, $this->db);
}
function __destruct() {
$this->mysqli->close();
}
public function query($query, $params = '', $bind_result) {
$stmt = $this->mysqli->prepare($query);
//Need to change this to process the array of params
$stmt->bind_param('i', $params);
$stmt->execute();
//Change this to handle array of bind
$stmt->bind_result($bind_result);
//Loop the result and store it in a temp array
$stmt->fetch();
//Don't print the statement. Just close the statement and return the array.
printf("%s\n", $bind_result);
/* close statement */
$stmt->close();
}
}
?>
I have to now create another class. I created one dummy table in database.
<?php
class Dummy {
private $database;
function __construct() {
$this->database = new Database();
}
public function getAllDummy() {
$query = "SELECT name FROM dummy WHERE id = ?";
$this->database->query($query, 1, 'name');
}
}
?>
But I don't think it is the right way to do the things. I feel some of them are in the right way and some of them are wrong.
When i call the query() function, Do i need to connect the database all the time in every classes' construct method? Or Do i need to change the Database class to static functions? So i can call the functions like Database::query();
It seems i need to create everything from the start. Is such a model already available in internet? like cakephp, codeigniter
I would like to recommend you to read something about ORM for PHP. For example I m using Doctrine 2 (http://www.doctrine-project.org/) It is kinda complex but definitely worth to learn. There is everything you are trying to code already done, so why you should make it again?
In your OOP principe there are some mistakes.
You are creating Database instance for every class like Dummy, if you will have class Users, Articles, you will create 3x Database, it isnt really good. You should make Database as service or Singleton and make it just once. Good solution for this can be Dependency injection (http://en.wikipedia.org/wiki/Dependency_injection).
Also I would recommend you to generalize whole Dummy class, to make it more general. Dont make method "getAllDummy" but for example "getAll($tableName)"so you can use it for every table.
Besides Doctrine (Which is powerfull and almighty already but still to complex) I can suggest you db.php (http://dbphp.net) which does everything what doctrine but is single file and is very easy to use. Cons: It is not well documented yet and has no big community yet.
What I'd like is to see the ideal framework for a system which has a group of objects (ie User) whereby the data is contained in a database. I've been advised to have a User class and a UserMapper class and this is my understanding of how it should look:
user.class.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;
}
public function __construct($userId, $email, $userGroup) {
$this->userId = $userId;
$this->email = $email;
$this->userGroup = $userGroup;
}
}
class UserMapper {
// database connection
private $db;
public function __construct($db)
{
$this->db = $db;
}
public function findByUserId ($userId) {
$userObject = new User();
$q = $this->db->prepare("SELECT userId, email, userGroup FROM user WHERE userId = :userId");
$q->bindValue(":userId", $id);
$q->setFetchMode( PDO::FETCH_INTO, $userObject);
$q->execute();
$q->fetch(PDO::FETCH_INTO);
return $userObject;
}
}
?>
main.php
<?php
include user.class.php;
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));
$getUser = new UserMapper($dbh);
$user = $getUser->findByUserId(41);
echo $user->getEmail();
?>
But this seems a bit messy in terms of the main.php side. Can I not make one PDO object and have that defined in all of my scripts? As well as a UserMapper object? Or do every time I want to get a user from the database do I need to make a NEW userMapper object, then do findByUserId (as above). Or is there a simpler way to doing this?
If I wanted to call a UserGroup object within the class User, how would I do this? (This would also need to connect to the database through PDO). To do the following seems messy:
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));
$getUserGroup = new UserGroupMapper($dbh);
$userGroup = $getUserGroupMapper->findByUserId($this->userGroup);
?>
one thing that i can think of is making this class a singleton, and create the $user above the declaration of the class, so whenever you include this class you'll have that user object.
Can I not make one PDO object and have that defined in all of my
scripts? As well as a UserMapper object?
You're actually looking for a Front Controller.
That is, in order to avoid the same instantiation of the same classes, you should have prepared them. Most people usually do this in bootstrap.php, that "tweaks" all required dependencies.
But a front controller implementation also includes a dispatcher and a router. I won't go deep into this, but focus on the problem you're trying to solve instead.
Factory pattern
It basically abstracts instantiation logic. The benefits are: 1) you can delay object instantiation 2) You avoid global state, which is bad for unit-testing. The simplified version of it would look like as:
class UserFactory
{
private $pdo;
private $cache = array();
public function __construct($pdo)
{
$this->pdo = $pdo;
}
public function build($mapper)
{
if (isset($this->cache[$mapper])) {
return $this->cache[$mapper];
} else {
// Inject an instance into a mapper
$instance = new $mapper($this->pdo);
// Save the state into a cache
$this->cache[get_class($instance)] = $instance;
return $instance;
}
}
}
And finally
A very simplified version of bootstrap-er would look like as,
<?php
/* File : bootstrap.php */
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));
// Include here UserFactory class
$userFactory = new UserFactory($dbh);
// Its kinda ready to be used
You would simply include in all scripts that need to access Users
<?php
/* File: main.php */
include(__DIR__ . '/bootstrap.php');
$getUser = $userFactory->build('UserMapper');
$user = $getUser->findByUserId(41);
echo $user->getEmail();
You need to use FETCH_CLASS instead and you don't need a userMapper just extend PDO then set the right fetch mode all in one class.
Don't forget to make the class definition available or use an autoloader
$this->statement->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE,"className");
FETCH_PROPS_LATE is there to get the constructor fired first in your class But you don't need a constructor in your case so just lose it. If you decide to keep it though than you should take a look here first.
Hope this helps good luck
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?
It is being said that "static methods are death to testability". If that is so, what is a viable alternative pattern for the below?
class User {
private $phone,
$status = 'default',
$created,
$modified;
public function __construct($phone) {
$this->phone = $phone;
$this->created = new DateTime;
$this->modified = new DateTime;
}
public static function getByPhone(PDO $pdo, $phone) {
$stmt = $pdo->prepare('SELECT * FROM `users` WHERE `phone` = :phone');
$stmt->execute(compact('phone'));
if (!$stmt->rowCount()) {
return false;
}
$record = $stmt->fetch(PDO::FETCH_ASSOC);
$user = new self($record['phone']);
$user->status = $record['status'];
$user->created = new DateTime($record['created']);
$user->modified = new DateTime($record['modified']);
return $user;
}
public function save(PDO $pdo) {
$stmt = $pdo->prepare(
'INSERT INTO `users` (`phone`, `status`, `created`, `modified`)
VALUES (:phone, :status, :created, :modified)
ON DUPLICATE KEY UPDATE `status` = :status,
`modified` = :modified');
$data = array(
'phone' => $this->phone,
'status' => $this->status,
'created' => $this->created->format('Y-m-d H:i:s'),
'modified' => date('Y-m-d H:i:s')
);
return $stmt->execute($data);
}
...
}
This is just a cut down example. The class has a few more methods and properties and there's more validation when writing to the database etc. The guiding design principle behind this class is that it models a user as an object. Some of the object's properties cannot be modified after it has been created, like the phone number (which acts as a primary id), the date the user was created and so on. Other properties can only be altered according to strict business rules, which all have strictly validating setters and getters.
The object does not represent a database record per se, the database is only seen as one possible form of permanent storage. As such, a database connector is not stored in the object but rather needs to be injected every time the object needs to interact with the database.
When a new user is created, this looks like:
$user = new User('+123456789');
When an existing user is restored from permanent storage, that looks like:
$pdo = new PDO('...');
$user = User::getByPhone($pdo, '+123456789');
If I were to take the "death to testability" line seriously, this is supposedly bad. I am perfectly able to test this object though, since it is fully dependency injected and the static methods have no state. How could I do this any differently and avoid the use of static methods? Or rather, what exactly argues against static in this case? What makes this particular use of static methods so hard to test?
This is mostly a summary of (my perspective of) the chat that ensued between me and #zerkms:
The point of contention is actually this:
public function doSomething($id) {
$user = User::getByPhone($this->pdo, $id);
// do something with user
return $someData;
}
This makes it hard to test doSomething since it hardcodes the User class, which may or may not have a lot of dependencies. But this is in fact the same as instantiating the object using a non-static method:
public function doSomething($id) {
$user = new User;
$user->initializeFromDb($this->pdo, $id);
// do something with user
return $someData;
}
We're not using a static method, but it's still unmockable. Actually, it got worse.
The answer is to use a factory:
public function doSomething($id) {
$user = $this->UserFactory->byPhone($id);
// do something with user
return $someData;
}
Now the factory can be dependency injected and mocked and the User class is no longer hardcoded. You may or may not think this overkill, but it certainly improves mockability.
That does not change the fact though that this factory may very well instantiate the actual user object using a static method:
public function byPhone($id) {
return User::getByPhone($this->db, $id);
}
There's no difference between using a static method or a regular constructor here.
$user = new User($db, $id);
$user = User::getByPhone($db, $id);
Both expressions return an instance of User and both "hardcode" the User class. Which simply needs to happen at some point anyway.
For my use case, a static constructor method makes the most sense for the object. And as was demonstrated, static methods are not the problem. Where to call them is the point of contention, not that they exist at all. And I have yet to see a convincing argument for not using static constructors, since they can be wrapped in a factory, which alleviates any problem with mockability, the same as it does for regular object instantiation.
As long as OP asked about general issue, and not asked how to improve his particular code - I'll try to answer using some abstract and tiny classes:
Well, it is not more difficult to test static methods themselves, but it is more difficult to test the methods that use static methods.
Let's see the difference on small example.
Let's say we have a class
class A
{
public static function weird()
{
return 'some things that depends on 3rd party resource, like Facebook API';
}
}
It does some work that requires setting up additional environment (specifying API keys in this case) and internet connection to FB API services. It will take some time to test this method (just because of network and API lags), but it is definitely easy enough to test it.
Now, we implement a class that uses A::weird() method:
class TestMe
{
public function methodYouNeedToTest()
{
$data = A::weird();
return 'do something with $data and return';
}
}
For now - we cannot test TestMe::methodYouNeedToTest() without additional steps required to make A::weird() worked. Yes, instead of testing methodYouNeedToTest we also need to do things that are not directly related to this class, but to another.
If we followed another way from the very begin:
class B implements IDataSource
{
public function weird()
{
return 'some things that depends on 3rd party resource, like Facebook API';
}
}
you see - the key difference here is that we implemented the IDataSource interface and made method normal, not static. For now we could rewrite our code above in this way:
class TestMe
{
public function methodYouNeedToTest(IDataSource $ds)
{
$data = $ds->weird();
return 'do something with $data and return';
}
}
And now we don't rely on specific implementation but we do on an interface. And now we can easily mock datasource.
Such abstractions help keeping our tests focusing more on the testing itself rather than on creating necessary environment.
Such steps helps us to have our unit tests fast. While we still could have acceptance, load and functional tests (but it is another story) that test that our application works as expected
Static methods are only "death to testability" if they depend on state. If you avoid writing such methods to begin with (which you should), then this issue simply goes away.
The Math.abs() example given is one of a good use of a static method. It does not depend on state, therefor it is super easily tested.
That said, whether or not you think static methods should be used is another story. Some people dislike their seemingly procedural nature. I agree with those who say that OOP is a tool, not a goal. If writing "proper" OO code doesn't make sense for a particular situation (e.g. Math.abs()), then don't do it. I promise the boogey man won't eat your application just because you used a static method. :-)
As mentioned in comments, I'd implement a repository pattern for this case.
For example, User would be a simple model with read-only properties
class User {
private $phone,
$status = 'default',
$created,
$modified;
public function __construct($phone) {
$this->setPhone($phone);
$this->created = new DateTime;
$this->modified = new DateTime;
}
private function setPhone($phone) {
// validate phone here
$this->phone = $phone;
}
public function getPhone() {
return $this->phone;
}
public function getCreated() {
return $this->created;
}
public function getModified() {
return $this->modified;
}
}
Your repository interface could then look like this
interface UserRepository {
/**
* #return User
*/
public function findByPhone($phone);
public function save(User $user);
}
A concrete implementation of this interface could look something like this
class DbUserRepository implements UserRepository {
private $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
public function findByPhone($phone) {
// query db and get results, return null for not found, etc
$user = new User($phone);
// example setting the created date
$reflectionClass = new ReflectionClass('User');
$reflectionProperty = $reflectionClass->getProperty('created');
$reflectionProperty->setAccessible(true);
$created = new DateTime($res['created']); // create from DB value (simplified)
$reflectionProperty->setValue($user, $created);
return $user;
}
public function save(User $user) {
// prepare statement and fetch values from model getters
// execute statement, return result, throw errors as exceptions, etc
}
}
The cool thing here is that you can implement many different repositories, all with different persistence strategies (XML, test data, etc)
I think the citation you give has a good point but takes too hard a line.
Your static method is what he calls a "leaf" method. In this case I think you are fine, as long as your static method doesn't have any external dependencies.
The alternative is a data mapper, an object which is aware of the relationship between User and how it is stored in the database. Example:
class UserDBMapper {
protected $pdo;
protected $userclass;
function __construct(PDO $pdo, $userclass) {
$this->db = $db;
// Note we can even dependency-inject a User class name if it obeys the interface that UserMapper expects.
// You can formalize this requirement with instanceof, interface_exists() etc if you are really keen...
$this->userclass = $userclass;
}
function getByPhone($phone) {
// fetches users from $pdo
$stmt = $this->db->query(...);
$userinfo = $stmt->fetch()....
// creates an intermediary structure that can be used to create a User object
// could even just be an array with all the data types converted, e.g. your DateTimes.
$userargs = array(
'name' => $userinfo['name'],
'created' => $userinfo['created'],
// etc
);
// Now pass this structure to the $userclass, which should know how to create itself from $userargs
return new $this->userclass($userargs);
}
function save($userobj) {
// save method goes in the Mapper, too. The mapper knows how to "serialize" a User to the DB.
// User objects should not have find/save methods, instead do:
// $usermapper->save($userobj);
}
}
This is a very powerful pattern (e.g., you need no longer have 1-1 type<->table, instance<->row correspondence like the Active Record pattern requires), and you can completely change your serialization method without altering your domain objects at all. It should also be obvious how much easier the mapper is to test. But in many cases this pattern is also over-engineered and more than you need. After all, most websites use the much simpler Active Record pattern.
Firstly, the DateTime class was a good (tricky) class to choose because it is a horrible class. All of its important work is done in the constructor and there is no way to set the date/time after it has been constructed. This requires us to have an objectGenerator that can build the DateTime object at the correct time. We can still manage this without calling new in the User class though.
I have kept things very simple to solve the problem at hand, but they can be extended easily to handle an arbitrarily complex problem.
Here is a simple objectGenerator to remove the coupling you get with new.
class ObjectGenerator {
public function getNew($className) {
return new $className;
}
}
Now we inject all of the dependencies into the constructor. The constructor shouldn't do real work, only set up the object.
class User {
private $phone,
$status = 'default',
$created,
$modified,
$pdo,
$objectGenerator;
public function __construct(PDO $pdo, $objectGenerator) {
$this->pdo = $pdo;
$this->objectGenerator = $objectGenerator;
$this->created = $this->objectGenerator->getNew('DateTime');
}
public function createNew() {
$this->phone = '';
$this->status = 'default';
$this->created = $this->objectGenerator->getNew('DateTime');
}
public function selectByPhone($phone) {
$stmt = $this->pdo->prepare('SELECT * FROM `users` WHERE `phone` = :phone');
$stmt->execute(compact('phone'));
if (!$stmt->rowCount()) {
return false;
}
$record = $stmt->fetch(PDO::FETCH_ASSOC);
$this->phone = $record['phone'];
$this->status = $record['status'];
$this->created = $record['created'];
$this->modified = $record['modified'];
}
public function setPhone($phone) {
$this->phone = $phone;
}
public function setStatus($status) {
$this->status = $status;
}
public function save() {
$stmt = $this->pdo->prepare(
'INSERT INTO `users` (`phone`, `status`, `created`, `modified`)
VALUES (:phone, :status, :created, :modified)
ON DUPLICATE KEY UPDATE `status` = :status,
`modified` = :modified');
$modified = $this->objectGenerator->getNew('DateTime');
$data = array(
'phone' => $this->phone,
'status' => $this->status,
'created' => $this->created->format('Y-m-d H:i:s'),
'modified' => $modified->format('Y-m-d H:i:s')
);
return $stmt->execute($data);
}
}
Usage:
$objectGenerator = new ObjectGenerator();
$pdo = new PDO();
// OR
$pdo = $objectGenerator->getNew('PDO');
$user = new User($pdo, $objectGenerator);
$user->setPhone('123456789');
$user->save();
$user->selectByPhone('5555555');
$user->setPhone('5552222');
$user->save();
So, no new or static in the user class. Try testing both solutions. The test code is a pleasure to write without the calls to new. All classes that use the User will also be easy to test without static calls to it.
The differences in test code are:
new/static - Require a stub for each new or static call to stop the unit from reaching outside of itself.
dependency injection - Mock objects can be injected. It is painless.
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);