Should mySQL INSERT be done in constructor? - php

I am starting to build a new project in PHP using OOP, and I have a dilemma about Object-Database relations.
For example, I have a User object. Should the constructor function already do the INSERT INTO... ? so I will call $user = new User($user_data);
Or should I have a different $user->save() method to do the INSERT?

Having a constructor perform an insert query doesn't sound like a good idea, IMHO. The User class, I think, should be regarded as a model, an object that collects data, which can be sent to a service layer. That's where the actual insert can be performed.
Just treat the User class as a type. Suppose an existing user logs in:
$login = new User(array('username' => $_POST['username'],
'pass' => $_POST['passwd']));
Then, inside the User class:
class User
{
const SALT = 'fo0bar';
private $_hash = null;
private $_name = null;
public function __construct (array $request, $login = false)
{
//this isn't the best hash in the world, of course...
$this->_hash = sha1($request['username'].SALT.$request['pass']);
$this->_name = $request['username'];
}
public function getHash()
{
return $this->_hash;
}
public function getName()
{
return $this->_name;
}
}
Nothing more than that, as far as the constructor goes. Just add more data if required, and some getters and setters. This object can then be passed to an object that has all db methods and holds the connection(s) you need, it can build a query using the hash and name getters, check if the user exists and perform an INSERT query if needed.

It will be better to use a separate 'method' for creating / saving a user.
The constructor will be executed every time you instantiate a User i.e use "user = new User()".
If inserted into your constructor a new user will be attempted to be created whenever a User object is created, which may well not be needed for the purpose you intend.

I would recommend having a separate save() function in your class for the following reasons
You have the opportunity to manipulate/amend object data before it is saved
When retrieving data, you will no doubt call $user->getAll(). So when initialising your user object, in this case - we don't want to be storing any data.
Try doing something like this
protected $_data;
public function __construct(array $data) {
$this->_data = $data;
}
public function save() {
//TODO: Save $data
return $this;
}
public function getAll() {
//TODO: Get from database and populate $this->_data
return $this->_data;
}

A common way of doing this is to separate model, and mapper. This means that User is an empty data store (model) - and you have a mapper which interacts with the object. Typical CRUD operations:
<?php
$model = new User();
$model->setName('Name');
$mapper->create($model);
$user = $mapper->find('Name');
$user->setName('NewName');
$mapper->update($user);
$model->delete($user);

Sometimes you may need to create an empty instance
php doesn't support overloading: Overloading would allow you to create a constructor which creates and empty instance.
You wouldn't want to insert an empty record for each object instance.
So I don't recommend adding an insert query to your constructor.

Related

Dependency Injection for class with array of objects as class attribute

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.

How to best fetch data with pdo as a getter

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?

PHP - The best way to load Database object from Model, but to have only one instance?

This is my problem, I have a tiny PHP MVC framework i built.
Now when Im in Controller, i should be able to load a Model.
I have Models named like database tables like Users.php, Pages.php etc.
All Controllers extend BaseController, and all Models extend BaseModel, this way I can have some methods available to all Controllers. Like from any Controller I can use loadModel method like this:
$usersModel = $this->loadModel("Users");
Now $usersModel will be object that represents users database table, and from there I should open database connection, and fetch, update, delete stuff from users table.
To get database connection from my Models, baseModel has method loadDatabase() and I use it like this:
$database = $this->loadDatabase();
This would return class that is thin layer around PDO so from there I can use something like this:
$data = $database->fetchAssoc("SELECT * FROM users WHERE name = ?", array("someone"));
This is how I would return some $data from Model to the Controller.
So basicly, Controller can load a model, and then call methods on that model that would return some data or update or delete etc.
Now, Controller can load more then one model. And each model should load database, and this is where it gets complicated. I need only one connection to the database.
This is how loadDatabase method looks:
public function loadDatabase()
{
// Get database configuration
require_once("Application/Config/Database.php");
// Build configuration the way Database Object expects it
$dns = "{$db_config['db_driver']}:host={$db_config['db_host']};dbname={$db_config['db_name']}";
$username = $db_config['db_user'];
$password = $db_config['db_pass'];
$options = $db_config['db_options'];
// Return new Database object
return new \Core\Database\Database($dns, $username, $password, $options);
}
So before I load a Database object, i must load configuration for database connection, as Database objects __constructor expects it. Then I instanciate new database object and return it.
Now Im stuck and I dont know is this the right way to loadDatabase from model?
How should I set this up, how should I load database from inside the model so there is always only one instance of database object. Beacuse if I do something like this from Controller:
$users = $this->loadModel("Users");
$pages = $this->loadModel("Pages");
$users->doSomethingThatNeedsDatabase();
$users->doSomethingThatNeedsDatabase();
$pages->doSomethingThatNeedsDatabase();
I would create 3 database objects :(
So my question is, how should I load Database from inside the Models, and how should that method look in BaseModel?
What if I would like to use 2 databases, I will have some big problems with this setup.
How can I achive this without using singleton pattern?
At the moment, I also have something like this:
public function getDatabase()
{
$reg = \Core\Registry\Registry::getInstance();
$db = $reg->getObject("database");
if(!isset($db))
{
require_once("Application/Config/Database.php");
$dns = "{$db_config['db_driver']}:host={$db_config['db_host']};dbname={$db_config['db_name']}";
$username = $db_config['db_user'];
$password = $db_config['db_pass'];
$options = $db_config['db_options'];
$db = new \Core\Database\Database($dns, $username, $password, $options);
$reg->setObject('database', $db);
}
return $reg->getObject('database');
}
This is Registry pattern, where I could hold shared objects. So when Model asks for DB connection I could check if DB Class is in Registry, and return it, if not I would instaciate and then return... The most confusing thing is that I need to load configuration array...
So what is the best way, to load Database from Models?
Thanks for reading, this was a very long question, but this is bothering me so much, i hope someone could help me with this one... Thanks!
You are going in the wrong way about solving this.
Instead of each time manually making a new "Model" and then configuring it, you should create a structure that does it for you ( extremely simplified version ):
class ModelFactory
{
protected $connection = null;
// --- snip --
public function __construct( $connection )
{
$this->connection = $connection;
}
// --- snip --
public function buildMapper( $name )
{
$instance = new {$name}( $this->connection );
return $instance;
}
// --- snip --
}
This class you would be using in index.php or bootstrap.php , or any other file you use as entry point for your application:
// at the bootstrap level
$modelFactory = new ModelFactory( new PDO(...) );
// i am assuming that you could get $controllerName
// and $action from routing mechanism
$controller = new {$controllerName}( $modelFactory );
$controller->{$action}();
The main problem you have is actually cause by misunderstanding what Model is. In a proper MVC the Model is a layer, and not a specific class. Model layer is composed from multitude of class/instances with two major responsibilities:
domain business logic
data access and storage
The instances in first group are usually called Domain Objects or Business Objects (kinda like situation with geeks and nerds). They deal with validations, computation, different conditions, but have no clue how and where information is stored. It does not change how you make an Invoice , whether data comes from SQL, remote REST API or a screenshot of MS Word document.
Other group consists mostly of Data Mappers. They store and retrieve information from Domain Objects. This is usually where your SQL would be. But mappers do not always map directly to DB schema. In a classic many-to-many structure you might have either 1 or 2 or 3 mappers servicing the storage. Mappers usually one per each Domain Object .. but even that is not mandatory.
In a controller it would all look something like this.
public function actionFooBar()
{
$mapper = $this->modelFactory->buildMapper( 'Book' );
$book = $this->modelFactory->buildObject( 'Book' );
$patron = $this->modelFactory->buildObject( 'Patron' );
$book->setTitle('Neuromancer');
$mapper->fetch( $book );
$patron->setId( $_GET['uid']);
if ( $book->isAvailable() )
{
$book->lendTo( $user );
}
$mapper->store( $book );
}
Maybe this will give you some indications for the direction in which to take it.
Some additional video materials:
Advanced OO Patterns (slides)
Global State and Singletons
Don't Look For Things!
Best way for these models to use dependency injection pattern.
public function loadModel() {
$db = $this->loadDatabase();
$model = new Model();
$model->setDatabase($db);
return $model;
}
where loadDatabase() should once init and after return simple instance of database connection.
Try this:
class Registry
{
/** #return Registry */
public static function getInstance() {}
public function getObject($key) {}
public function setObject($key, $value) {}
/** #return bool */
public function isObjectExists($key) {}
}
class Db
{
const DB_ONE = 'db_one';
const DB_TWO = 'db_two';
protected static $_config = array(
self::DB_ONE => array(),
self::DB_TWO => array(),
);
public static function getConnection($dbName) {}
}
abstract class BaseModel
{
abstract protected function _getDbName();
protected function _getConnection()
{
$dbName = $this->_getDbName();
if (!Registry::getInstance()->isObjectExists($dbName)) {
Registry::getInstance()->setObject($dbName, Db::getConnection($dbName));
}
return Registry::getInstance()->getObject($dbName);
}
}
class UserModel extends BaseModel
{
protected function _getDbName()
{
return Db::DB_ONE;
}
}
class PostModel extends BaseModel
{
protected function _getDbName()
{
return Db::DB_TWO;
}
}
Good luck!

Zend Session Identity losing object parameters

I have a strange problem I can't seem to track down.
I have a custom class ("Person") extending Zend_Db_Table_Row_Abstract that represents a user.
Among other things, this class has custom variables that are set in the init() method, for instance:
class Person extends Zend_Db_Table_Row_Abstract
{
protected $_cdata = array(); // non-db-table data gets put here through __set()
public function init()
{
$this->fullName = $this->firstName." ".$this->lastName; // this is saved to $this->_cdata['fullName']
}
Upon login, I store an object of this class as Zend Auth Identity:
$r = $auth->authenticate($authAdapter);
if($r->isValid())
{
$user = $db->getUserByEmail($email); // Retrieves an object of class "Person"
$auth->getStorage()->write($user);
}
Now, if I call Auth Identity in the same action request as the login, it will work alright:
echo $user->fullName; // Will print "John Smith" or whatever it is
However, when I call another action, and call Auth Identity, I lose whatever I have stored in "_cdata" array:
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity() {
$user = $auth->getIdentity();
echo $user->fullName; // Prints nothing...$_cdata['fullName'] does not exist.
}
Any ideas?
The reason why that's happening is because Zend_Auth identity data gets serialized (and deserialized) between requests.
Which leads us to a closer look onto __sleep method of Zend_Db_Table_Row_Abstract class, which is the one that gets called once $user object is serialized.
public function __sleep()
{
return array('_tableClass', '_primary', '_data', '_cleanData', '_readOnly' ,'_modifiedFields');
}
What you need to do is to override this method in your Person class, so that it includes $_cdata array as well. Then this property will be serialized and available in the next HTTP request.

What are other PHP class designs for DB object interactions?

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.

Categories