I have the following class for all my user methods:
class User {
protected $_db,
$_data;
public function __construct($user = null, $findby = 'id') {
$this->_db = DB::getInstance();
if (!$user) {
........
} else {
........
}
}
.......
public function login($username = null, $password = null) {
$user = $this->find($username, 'username');
if ($user) {
$lockdown = new Lockdown;
}
}
public function find($param = null, $method = null) {
if ($param && $method) {
$data = $this->_db->query("SELECT * FROM users ...");
if ($data->count()) {
$this->_data = $data->result();
return true;
}
}
return false;
}
public function data() {
return $this->_data;
}
}
The above is a completely stripped down version of my user class. I also have another class (lockdown) which extends user:
class Lockdown extends User {
public $getAttempts;
public function __construct() {
var_dump($this->data());
die();
}
}
However when i call the lockdown class inside of the login class, even though the data object should contain all the user information, the var_dump() is simply returning NULL.
From my calculations when the login class is called, the find method should set $_data = USER INFO, which should therefore allow the new Lockdown method invoked just after the ($this->find()) to be able to access the same data method.
I am still learning OOP Programming so don't know if there is something i am missing, but i can't seem to understand the reason as to why the Lockdown class returns NULL on the data method when it should inherit it.
You should not put any computation logic inside a constructor. It makes it hard to test. You also cannot return from a constructor.
You structure is a complete disaster. Both because of your abuse of the inheritance and of global state.
It makes no sense for a class to create a new instance of its own child class for retrieving data. This is probably a result of you attempting to for a User class to combine two different responsibilities: persistence and business logic. This constitutes a violation of Single Responsibility Principle, which then manifest in a form of a convoluted call graph.
Also the whole class Lockdown extends User construct makes no sense. The extends keyword in OOP can be translates as "is special case of" (as per LSP). The class for tracing user's login attempts is not a specialized case of "user".
You should have at least 3 separate classes for this: one for handling the "user's behavior" and other for saving/restoring "user's state" (the approach is called "data mapper"). The third one would be for managing the the failed attempts.
I would also highly recommend watching this lecture.
As for global state, instead of using a singleton anti-pattern, you should have passed the database connection as a constructor's dependency to the class, which need to interact with persistence.
As for the code, at a high level, it should probably looks something like this:
$user = new User;
$mapper = new UserMapper($db);
$user->setName($username)
if ($mapper->fetch($user)) {
if ($user->matchPassword($password)) {
// you have logged in
// add some flag in session about it
header('Location: /greetings');
exit;
}
// check the failed attempts
} else {
// no matching username
}
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 created this class that fetches all data of a post from database.
class Post {
private $id;
protected $conn;
public $data;
function __construct(\mysqli $conn) {
$this->conn = $conn;
}
public function getId() {
return $this->id;
}
public function getConnection() {
return $this->conn;
}
public function getPost() {
$query1 = $this->getConnection()->query("SELECT * FROM posts WHERE id=" . $this->id);
if ($query1->num_rows == 1) {
$this->data = $query1->fetch_object();
return $this->data;
}
}
public function setId($id) {
$this->id = (int)$id;
}
}
Along with post, I also need to fetch all data of the user who created the post. I've three ways to do this:
1) By calling the User class inside of the Post class.
public function getPost() {
$query1 = $this->getConnection()->query("SELECT * FROM posts WHERE id=" . $this->id);
if ($query1->num_rows == 1) {
$this->data = $query1->fetch_object();
// Initiating User class
$user = new User($this->getConnection());
$user->setUserId($this->data->user_id);
$this->data->user = $user->getUserInfo();
return $this->data;
}
}
2) By extending the Post class with the User class.
class Post extends User {
....
Then calling methods from the User class
public function getPost() {
$query1 = $this->getConnection()->query("SELECT * FROM posts WHERE id=" . $this->id);
if ($query1->num_rows == 1) {
$this->data = $query1->fetch_object();
// Calling methods from the User class
$this->setUserId($this->data->user_id);
$this->data->user = $this->getUserInfo();
return $this->data;
}
}
3) By creating a User trait and using it in Post class.
class Post {
use UserTrait;
....
Then calling methods from the User trait
public function getPost() {
$query1 = $this->getConnection()->query("SELECT * FROM posts WHERE id=" . $this->id);
if ($query1->num_rows == 1) {
$this->data = $query1->fetch_object();
// Calling methods from the User trait
$this->setUserId($this->data->user_id);
$this->data->user = $this->getUserInfo();
return $this->data;
}
}
Between these 3, which one is the best approach in terms of dependency injection, performance, and cleanliness of code?
This question might get downvoted to hell because you're requesting an opinion, but I'll throw in my two cents.
You're basically building your own basic ORM. In that ORM you're dealing with entities. Different entities should be handled by different classes (Models), and there should be a 1:1 equivalence between the underlying DB table and the Model.
There are relations between your entities. Yous Post entity has an author that should be an instance of the User entity. However, you wouldn't say that the relation between the post table and the user table means they could be represented by the same Model, or different flavors of a parent Model.
If you used a full ORM (Doctrine, Propel, RedbeanPHP) you'd see that a relation such as the Post author means that, when using methods like getById() (in your case getPost() ) the retrieved Post entity will proceed to instance every depending entity by default.
In your case, instead of having $this->data->user_id the ORM would offer you a nested $this->data->user object so you wouldn't have to deal with that by yourself.
So, if you consider it's too soon to use an ORM, the first approach is easier to mantain and migrate when the time comes.
Unrelated opinion
At this point, to get a post info you need to do
$post = new Post($conn);
$post->setId($postid);
$postdata = $post->getPost();
If you changed your constructor and added a getById() method such that
function __construct(\mysqli $conn) {
$this->conn = $conn;
return $this;
}
public function getById($id) {
$this->setId($id);
return $this->getPost();
}
you could instead retrieve the post data in one line
$postdata=(new Post($conn))->getById($postid);
It all depends on what you're going to keep doing it. With the extended class was better deal if you're going to use permanent methods of other classes. If you need only a part of another class, then just call the class and its method.
CAREFUL: An extended class behaves as a single class. Here can be a lot of collisions occur if you have the same names of methods and functions.
I think this depends on other aspects of your code. Personally I would just extend the class User as I don't think using traits is necessary in this particular case.
There is a useful article here on using Traits in PHP -
Using Traits in PHP 5.4
EDIT: To clear up some confusion, I am not actually using Male and Female. A better example would be parent-class Animal and sub-classes Cat and Dog.
I'm kind of new to OOP, but I've grasped it pretty well so far. However, there's one thing I can quite find a way of doing.
Firstly, I create a create a new object based around the user. The user can be be (for this example) male or female, but I cannot check if they are without checking in the database. I then need to create a new user object with the sub-class of their sex.
For example, here is my current (messy) code:
$user = new Person();
$userType = $user->GetUserType($userid);
if ($userType == 'Male') {
$user = new Male($userid);
} else {
$user = new Female($userid);
}
If I want to make a new object, I must do this every time, which is something I don't want to have to do.
Here's a little more code to help put this into perspective:
class Person {
function GetUserType($userid) {
$db = mysqlConnect();
$stmt = $db->stmt_init();
// Get the players information
$stmt->prepare("SELECT user_type FROM user_information WHERE user_id = ?");
$stmt->bind_param('i', $userid);
$stmt->execute();
$stmt->bind_result($userType);
$stmt->fetch();
$stmt->close();
$db->close();
return $userType;
}
}
class Male extends Person {
// Male based things here
}
class Female extends Person {
// Female based things here
}
So, in the __construct of the Person class, I'd like it to check for the users sex and set the appropriate sub-class.
So, in the __construct of the Person class, I'd like it to check for the users sex and set the appropriate sub-class.
Like already said elsewhere, ctors do not return, so you cannot do that. And ctors should not query the database anyway, because that would be doing work. If you cannot/want not create the correct subtype immediately via DataMapper or Repository, you can use a State Pattern:
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
This is one of the Behavioral Patterns from the Gang Of Four book. The keyword, obviously, is behavior here. The State pattern is not about varying Subtypes (Cat, Dog) as such, but rather about the difference in the behavior those have. Hence my comments to your question.
Example:
interface GenderBehavior
{
public function someBehavior();
// can add more methods here
}
class FemalePersonBehavior implements GenderBehavior
{
public function someBehavior()
{
// female specific behavior
}
}
class MalePersonBehavior implements GenderBehavior
{
public function someBehavior()
{
// male specific behavior
}
}
class UnknownGenderBehavior implements GenderBehavior
{
public function someBehavior()
{
// either implement a neutral behavior or
throw new LogicException('Unknown Gender set');
}
}
To create those instances, you add a Factory
class GenderBehaviorFactory
{
public static function create($sex = null)
{
switch ($sex) {
case 'male':
return new MalePersonBehavior;
case 'female':
return new FemalePersonBehavior;
default:
return UnknownGenderBehavior;
}
}
}
Then you add the GenderBehavior interface to the Person class and tunnel all access to the interface methods to the Behavior instance:
class Person implements GenderBehavior
{
private $behavior;
public function __construct()
{
$this->behavior = GenderBehaviorFactory::create();
}
public function changeGender($sex)
{
$this->behavior = GenderBehaviorFactory::create($sex);
}
public function someBehavior()
{
$this->behavior->someBehavior();
}
}
Now when you create a Person the first time, it will instantiate with an UnknownGenderBehavior and if you try to call someBehavior, it will raise an Exception. When you call changeGender with either male or female as argument, the appropriate GenderBehavior will be created and set to Person. And then you can call someBehavior.
You cannot choose what to return from a constructor, but you can take your hierarchy as is (Person is of unknown gender, Male and Female are known) and use something like this pattern:
public class Person {
public function ensureHasGender() {
if ($this instanceof Male || $this instanceof Female) {
return $this;
}
// now construct a Male or Female object from $this and return it
$userType = $user->GetUserType($this->userid);
return new $userType($this->userid);
}
}
So you can now call $user->ensureHasGender() as many times as you like and it will only construct a gender-specific instance the first time.
However, I think this strategy is questionable. What do you stand to gain from having separate Male and Female classes? If their behavior were so much different then this could be justified, but that doesn't sound too likely. Perhaps handling the issue internally in the class with lazy loading and appropriate conditionals would be better.
For the sake of simplicity, assume I have 2 classes, User and UserStatus, used in a Web application.
<?php
// library code:
class UserStatus {
protected $_status = NULL;
private function fetchDataFromDB() {
// regular DB stuff
$this->_status = ...
// result will be something like 'online', 'away', etc.
}
public function getIcon() {
global $icon_array;
if (is_null($this->_status)) {
$this->fetchDataFromDB()
}
return $icon_array[$this->_status];
}
}
class User {
protected $user_id;
public $user_name;
protected $status;
public function __construct() {}
public static function getAll() {
// some DB stuff
return $users;
}
}
// and now, in index.php:
$users = User::getAll();
// echoes the icon to use to reflect the current user status
foreach ($users as $user) {
echo <img src="$user->status->getIcon()"/>;
}
?>
In most of the HTTP request the status object will not be used so I'm looking for a way to only instantiate it as needed (call it lazy loading). How should I intercept the status->method() call and create that object on-the-fly?
An important note is that I need $user_id available in the UserStatus class, otherwise the fetchDataFromDB() method won't know to which user it should fetch the data. How should this be done?
I've looked at some interesting stuff on this matter like Fabien Potencier's What is Dependency Injection? and Pimple - a PHP 5.3 dependency injection container and also some articles about the Proxy Pattern but to implement them it looks like I have to mess a lot with the current code. Is there a simpler way?
Maybe im missing something but it seems the easiest solution in this instance would be to have your getter for Status simply create the object if it doesnt exist...
public function getStatus()
{
if(!isset($this->status))
{
// or however you creat this object..
$this->status = new UserStatus($this->user_id);
}
return $this->status;
}
public function __get($property)
{
$method = 'get'.ucfirst($property); // getStatus
if(method_exists($this, $method))
{
return $this->$method();
}
}
By using the __get magic method anytime you do $user->status it will call $user->getStatus(). Ofcourse you could also always just access it like: $user->getStatus()->getIcon() as well.
However you decide to set up accessing your properties i would recommend doing it in a consistent way across your entire model.
You could put the status class in a different file and then leverage php's autoloading mechnism:
http://php.net/manual/de/language.oop5.autoload.php
to not load that file until you access it.
There are rumors that auto loading (or actually just any kind of conditional loading) is troublesome for byte code caches and optimizers though unfortunately I don't know too much about the impact.
P.S.: The manual does not say rhis explicity at this point: You can also use spl_autoload_register() instead of just defining the magic __autoload function. This is slightly more powerful.
I'm working on creating a domain layer in Zend Framework that is separate from the data access layer. The Data Access Layer is composed to two main objects, a Table Data Gateway and a Row Data Gateway. As per Bill Karwin's reply to this earlier question I now have the following code for my domain Person object:
class Model_Row_Person
{
protected $_gateway;
public function __construct(Zend_Db_Table_Row $gateway)
{
$this->_gateway = $gateway;
}
public function login($userName, $password)
{
}
public function setPassword($password)
{
}
}
However, this only works with an individual row. I also need to create a domain object that can represent the entire table and (presumably) can be used to iterate through all of the Person's in the table and return the appropriate type of person (admin, buyer, etc) object for use. Basically, I envision something like the following:
class Model_Table_Person implements SeekableIterator, Countable, ArrayAccess
{
protected $_gateway;
public function __construct(Model_DbTable_Person $gateway)
{
$this->_gateway = $gateway;
}
public function current()
{
$current = $this->_gateway->fetchRow($this->_pointer);
return $this->_getUser($current);
}
private function _getUser(Zend_Db_Table_Row $current)
{
switch($current->userType)
{
case 'admin':
return new Model_Row_Administrator($current);
break;
case 'associate':
return new Model_Row_Associate($current);
break;
}
}
}
Is this is good/bad way to handle this particular problem? What improvements or adjustments should I make to the overall design?
Thanks in advance for your comments and criticisms.
I had in mind that you would use the Domain Model class to completely hide the fact that you're using a database table for persistence. So passing a Table object or a Row object should be completely under the covers:
<?php
require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();
$db = Zend_Db::factory('mysqli', array('dbname'=>'test',
'username'=>'root', 'password'=>'xxxx'));
Zend_Db_Table_Abstract::setDefaultAdapter($db);
class Table_Person extends Zend_Db_Table_Abstract
{
protected $_name = 'person';
}
class Model_Person
{
/** #var Zend_Db_Table */
protected static $table = null;
/** #var Zend_Db_Table_Row */
protected $person;
public static function init() {
if (self::$table == null) {
self::$table = new Table_Person();
}
}
protected static function factory(Zend_Db_Table_Row $personRow) {
$personClass = 'Model_Person_' . ucfirst($personRow->person_type);
return new $personClass($personRow);
}
public static function get($id) {
self::init();
$personRow = self::$table->find($id)->current();
return self::factory($personRow);
}
public static function getCollection() {
self::init();
$personRowset = self::$table->fetchAll();
$personArray = array();
foreach ($personRowset as $person) {
$personArray[] = self::factory($person);
}
return $personArray;
}
// protected constructor can only be called from this class, e.g. factory()
protected function __construct(Zend_Db_Table_Row $personRow) {
$this->person = $personRow;
}
public function login($password) {
if ($this->person->password_hash ==
hash('sha256', $this->person->password_salt . $password)) {
return true;
} else {
return false;
}
}
public function setPassword($newPassword) {
$this->person->password_hash = hash('sha256',
$this->person->password_salt . $newPassword);
$this->person->save();
}
}
class Model_Person_Admin extends Model_Person { }
class Model_Person_Associate extends Model_Person { }
$person = Model_Person::get(1);
print "Got object of type ".get_class($person)."\n";
$person->setPassword('potrzebie');
$people = Model_Person::getCollection();
print "Got ".count($people)." people objects:\n";
foreach ($people as $i => $person) {
print "\t$i: ".get_class($person)."\n";
}
"I thought static methods were bad
which is why I was trying to create
the table level methods as instance
methods."
I don't buy into any blanket statement that static is always bad, or singletons are always bad, or goto is always bad, or what have you. People who make such unequivocal statements are looking to oversimplify the issues. Use the language tools appropriately and they'll be good to you.
That said, there's often a tradeoff when you choose one language construct, it makes it easier to do some things while it's harder to do other things. People often point to static making it difficult to write unit test code, and also PHP has some annoying deficiencies related to static and subclassing. But there are also advantages, as we see in this code. You have to judge for yourself whether the advantages outweigh the disadvantages, on a case by case basis.
"Would Zend Framework support a Finder
class?"
I don't think that's necessary.
"Is there a particular reason that you
renamed the find method to be get in
the model class?"
I named the method get() just to be distinct from find(). The "getter" paradigm is associated with OO interfaces, while "finders" are traditionally associated with database stuff. We're trying to design the Domain Model to pretend there's no database involved.
"And would you use continue to use the
same logic to implement specific getBy
and getCollectionBy methods?"
I'd resist creating a generic getBy() method, because it's tempting to make it accept a generic SQL expression, and then pass it on to the data access objects verbatim. This couples the usage of our Domain Model to the underlying database representation.