Reputation: 1791
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?
Upvotes: 1
Views: 1558
Reputation: 21671
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.
Upvotes: 3
Reputation: 948
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.
Upvotes: -2