Another question trying to verify the understanding of OOP dependencies of classes.
Although I knew PHP 4.* quite well, I have only recently restarted programming, and thus started working on OOP so please be gentle ;)
Classes should be as independent as possible I understand. So, when I have a class institute that gets information from a database, I would have to inject institute with an instance of the database class, right?:
$dbh = new database();
$a = new institute();
$a->SetDBI($dbh);
In database, I have a method pulling one record from the database, and is fed with the table table, the ID column and the actual ID of the record to be pulled.
Now, say I want one method in Institute that gets one institute. To me it would make sense to then use the database class method getone():
public function GetInstitute()
{
$record = $this->dbi->GetOneRecord('table', 'column', $this->id);
}
Is this the right way of going about it? It feel that I am still building dependencies between classes this way?
The question is: am I building dependencies that should not be here? Or is it standard practice to use methods from one class in another class, as shown in the example?
This is right. You still have some dependencies between classes, but only to a certain degree. Actually (because of PHP's weak typing), you can pass any class, and it will work as long as it implements the GetOneRecord method properly.
To make it a little more strict, you can use a base class or an interface and add type hinting to the setDBI method, but otherwise, this is the way to go.
But for the implementation detail, I'm not so sure. I see you pass a table name and column name to the database object. That is not right. You don't want your Institution to know how and where it is saved. I'd rather see that you passed an object implementing a LoadInstitution($id) method. But I find it hard to give you a solid example, because it's unclear to me what GetInstitute is meant to do in the first place.
Related
Hey Guys
I know Stackoverflow is may not the right place to ask, if there's another Stackexchange group where
this question fits better, then please tell me.
So, I'm trying to learn OOP. I think I understand it quite good, but there's one thing I really can't figure
out what the right way is, and thats the handling of database.
So, I'm confused a bit of what should go in which class.
Lets say I've a db class. Inside of this class I'm connecting to the database in a constructor. And now lets say
I've got a user class.
So now the question:
Where should I put in the query for example creating a new user? Should i create a method in the user class,
or should I create a method in the DB class? If in DB class, should it really be a method like create_user()
or should it more be something globally like query where I can pass in whatever query I want.
Here, for example a project from Github:
https://github.com/christran/PHP-OOP-Login-Register-System/blob/master/classes/user.php
As you can see, all query methods are in db.php and from user.php he's just calling this methods. So is this the right way to go?
Or doesn't it matter at all? May, any of those approches is "more" OOP than the other?
It's actually just really confusing me and I don't understand whats the better way. I've searched a lot, but never
found an article to this specific question.
So what I did, I looked for projects on Github and looked at their code, how they've solved the problem...
But with this method I just got confused even more, because you see both.
Is it just a preference of the coder?
I am really thankful for all your help. Have a nice day! :)
Here a little example of what I mean:
Query inside user class:
class user {
private function createUser() {
//SQL Query here (prepared statements etc...)
}
}
OR:
class user {
private function createUser() {
// Call to db.class to insert_method() ...
}
}
Basically, you are looking into ORM.
To answer your question specifically,
Should i create a method in the user class
This is possible, and is called Active record pattern, where an entity contains not only methods related to itself (like $user->getBirthday()) but also methods that related to database interaction (like $user->save()).
or should I create a method in the DB class?
This is impossible, as this class will become enormously big.
However, you can create a sister class for the every entity, that will be responsible for the database interaction. This approach is called Data Mapper pattern. For example, there is a User class that contains methods related to the user, and also a UserMapper class, that is inherited from abstract mapper class with generic methods $userMapper->save(), $userMapper->find() and such.
The createUser method that contains the query shouldn't be part of the User object, but neither of the database object. The first one is for business logic. The latter one is for managing the database method and providing generic functionality for executing statements. A different object inbetween those objects should be the one that takes the data from the user object and generate the queries for storing it in the database.
The term I think you're looking for here is ORM (Object-relational mapping).
This concept is about mapping objects to a different, incompatible structure, like a database.
There are ORM libraries/frameworks available for PHP which can do much of the work for you, and some of them are part of, or can be used with, popular MVC frameworks like Eloquent ORM in Laravel. For example, they will often provide the basic CRUD operations by implementing the SQL statements needed after you just configure the right database table.
In terms of OOP, you will often have an extra layer on top of it. So you got a business object User, which contains the rules for users, for instance rules it has to follow for a user name. The business object will enforce those rules and contain the general behaviour of a User object. For saving you make use of an ORM to save a user object to a specific database. The database logic is not in the User object itself. It shouldn't have to know about the specific queries to save itself, and maybe it shouldn't even be aware of concepts like loading and saving. It just contains logic and data, and other parts of the implementation are responsible for persisting that data (optionally using an ORM framework to make things easier).
I was starting a project today and after designing the database structure and how the data would be stored etc, I started the implementation. I am doing this on php, but the language isn't really relevant here, since my doubts are more architectured related or I guess, since I'm struggling more than I thought by implenting stuff in OOP on PHP. (Recently jumped on php, I've been coding in c++ and java before).
So, I started by creating my "User" class, simple as that, few attributes, and __construct, insert, update and delete methods. Those last 3, queries to the db.
Then this doubt came to my head, and I probably know the answer myself but I just don't find out.
I can now create instances and create new Users: $user = new User("John", 34) but, what if I want to edit the user "Dave"? Or I want to show all users. That method, for example, getAllUsers() which would return all users where would be implemented? Because it doesn't really belong to the class User does it? If it did, then how I would instance that method if I don't have any User instance?
I guess, I would need a class Users, or UserCollection which would be a collection of all the users, with the methods ´getCertainUser(id)´ and ´getAllUsers()´ which would return certain User or All of them, now then I would have a User I would be able to edit, right?
That being said, my questions is, how this problem should be addressed as the way to go, Am I complicating things too much? How this should be solved 'the correct way' in OOP. The times I've handled similar problems I've never used a database, so having a collection of users was the only way to store them, but having the database which stores the users feels redundant to have that collection of users.
Thanks in advance.
First, you are doing the right thing, by challenging yourself.
Obviously, there are many ways of doing things.
I highly believe that trying to keep concerns separated as much as possible and keeping classes small and simple are always two good guidelines when you want to write code that is easy to maintain and to test.
This would be one way of doing it :
To handle Models & Structures
Entity/User (Define the properties of a user)
Collection/User (implements ArrayIterator, just a structure)
To handle communication with your repository (db).
Repository/Mysql/User (implements getAllUsers, saveUser, deleteUser, etc.)
Those classes should implements common interfaces or inherit common abstract classes (if they share common logic).
For the basic persistency operation (update, delete, create), I have a little preference of moving them in the repository class instead of the entity. I prefer to avoid using "smart" entity objects. In my mind, it makes more sense. But, there are plenty of people who would disagree (and there is really no right or wrong here).
I have a Data Model structure similar to yours, where classes represent their table counterparts. In the case of retrieving multiple of a "User" or "Categories", etc, I have a static method inside the class, that returns instances of the class. In example:
class User{
public static function fetchUsersForBusiness(Business $business){
//fetch code here into variable $users from database...
$userObjs = [];
foreach($users as $userData){
$userObjs[] = new User($userData);
}
return $userObjs;
}
}
class Business{
}
The following code would return all the users that fit a certain criteria (in this case, a business they're associated with). I then return them as the objects themselves.
I've found this model to be fairly successful, and have used it in a multitude of languages including Java, PHP, and Swift. Hope it helps you.
Please note I'm not looking for 'use a framework' answers. I'm trying to structurally improve the way I code websites and approach databases from PHP.
I'm building a web service from scratch, without any frameworks. I'm using a LAMP stack and am trying to learn a bit of PHP's OO functionality while I'm at it. I've previously only used OO to make mobile apps.
I've been at it for months now (as planned, no worries). Along the way I've bumped into a couple of structural problems, making me wonder what the best way would be to make the code object oriented.
Pretty much all of the problems involve the database in some way. Say we have a class DB and a class User. In most cases I only need to fetch a single user's information from the database. I thought a good way to handle it was to have a global $_db variable and have the User object query the database like so (oversimplified):
class User {
function __construct($id) {
global $_db;
$q = $_db->query("SELECT name, mail FROM user WHERE id = ?", $id);
$this->loadProperties($q);
}
}
Now say we have a page that shows a list of users. I still want to make User objects for each of them, but I don't want to query the database for each separate user.
So, I extend the User class to take an object as an argument:
class User {
function __construct($id) {
if(is_object($id))
$q = $id;
else {
global $_db;
$q = $_db->query("SELECT name, mail FROM user WHERE id = ?", $id);
}
$this->loadProperties($q);
}
}
Now I can create a list of, for example, the 100 most recently created and active accounts:
$user_list = [];
$q = $_db->query("SELECT name, mail FROM user WHERE banned = 0 ORDER BY date_created DESC LIMIT 100");
while($a = $_db->fetch($q))
$user_list[] = new User($a);
This all works great, except for one big downside: the database queries for table user are no longer in one place, which is kind of making spaghetti code. This is where I'm starting to wonder whether this can be done more efficiently.
So maybe I need to extend my DB object instead of my User object, for example:
class DB {
public function getUsers($where) {
$q = $this->query("SELECT name, mail FROM user WHERE ".$where);
$users = [];
while($a = $this->fetch($q))
$users[] = new User($a);
}
}
Now I would create the user list as follows:
$user_list = $_db->getUsers("banned = 0 ORDER BY date_created DESC LIMIT 100");
But now I'm calling the getUsers() method in various places using various SQL queries, solving nothing. I also don't want to load the same properties each time, so my getUsers() method will have to take entire SQL queries as an argument. Anyway, you get the point.
Speaking of loading different properties, there's another thing that has been bugging me writing OO in PHP. Let's assume our PHP object has at least every property our database row has. Say I have a method User::getName():
class User {
public function getName() {
return $this->name;
}
}
This function will assume the appropriate field has been loaded from the database. However it would be inefficient to preload all of the user's properties each time I make an object. Sometimes I'll only need the user's name. On the other hand it would also be inefficient to go into the database at this point to load this one property.
I have to make sure that for each method I use, the appropriate properties have already been loaded. This makes complete sense from a performance perspective, but from an OO perspective, it means you have to know beforehand which methods you're gonna use which makes it a lot less dynamic and, again, allows for spaghetti code.
The last thing I bumped into (for now at least), is how to separate actual new users from new User. I figured I'd use a separate class called Registration (again, oversimplified):
class Registration {
function createUser() {
$form = $this->getSubmittedForm();
global $_db;
$_db->query("INSERT INTO user (name, mail) VALUES (?, ?)", $form->name, $form->mail);
if($_db->hasError)
return FALSE;
return $_db->insertedID;
}
}
But this means I have to create two separate classes for each database table and again I have different classes accessing the same table. Not to mention there's a third class handling login sessions that's also accessing the user table.
In summary, I feel like all of the above can be done way more efficiently. Most importantly I want pretty code. I feel like I'm missing a way to approach the database from an OO perspective. But how can I do so without losing the dynamics and power of SQL queries?
I'm looking forward to reading your experiences and ideas in this field.
Update
Seems most of you condemn my use of global $_db. Though you've convinced me this isn't the best approach, for the scope of this question it's irrelevant whether I'm supplying the database through an argument, a global or a singleton. It's still a separate class DB that handles any interaction with the database.
It's a common thing to have a separate class to handle SQL queries and to keep the fetched data. In fact, it is the real application of the Single Responsibility Principle.
What I usually do is keep a class with all the information concerning the data, in your case the User class, with all the user information as fields.
Then comes the business layer, for instance UserDataManager (though the use of "Manager" as a suffix is not recommended and you'd better find a more suitable name in each scenario) which takes the pdo object in its constructor to avoid use of global variables and has all the SQL methods. You'd thus have methods registerNewUser, findUserById, unsuscribeUser and so on (the use of "User" in the method can be implied by the class name and be omitted).
Hope it helps.
I've liked to use the data mapper pattern (or at least I think that's how I'm doing it). I've done this for some sites built on Silex, though it's applicable to going without a framework since Silex is very lightweight and doesn't impose much on how you architect your code. In fact, I recommend you check out Symfony2/Silex just to get some ideas for ways to design your code.
Anyway, I've used classes like UserMapper. Since I was using the Doctrine DBAL library, I used Dependency injection to give each mapper a $db. But the DBAL is pretty much a wrapper on the PDO class as far as I understand, so you could inject that instead.
Now you have a UserMapper who is responsible for the CRUD operations. So I solve your first problem with methods like LoadUser($id) and LoadAllUsers(). Then I would set all the properties on the new User based on the data from the database. You can similarly have CreateUser(User $user). Note that in "create", I'm really passing a User object and mapping it to the database. You could call it PersistUser(User $user) to make this distinction more clear. Now all of the SQL queries are in one place and your User class is just a collection of data. The User doesn't need to come from the database, you could create test users or whatever else without any modification. All of the persistence of `User is encapsulated in another class.
I'm not sure that it's always bad to load all of the properties of a user, but if you want to fix that, it's not hard to make LoadUsername($id) or other methods. Or you could do LoadUser($id, array $properties) with a set of properties taht you want to load. If your naming is consistent, then it's easy to have set the properties like:
// in a foreach, $data is the associative array returned by your SQL
$setter = 'set'.$property;
$user->$setter($data[$property]);
Or (and?) you could solve this with Proxy objects. I haven't done this, but the idea is to return a bunch of UserProxy objects, which extend User. But they have the Mapper injected and they override the getters to call into the Mapper to select more. Perhaps when you access one property on a proxy, it will select everything via the mapper (a method called populateUser($id)?) and then subsequent getters can just access the properties in memory. This might make some sense if you, for example, select all users then need to access data on a subset. But I think in general it may be easier to select everything.
public function getX()
{
if (!isset($this->x)) {
$this->mapper->populateUser($this);
}
return $this->x;
}
For new users, I say just do $user = new User... and set everything up, then call into $mapper->persist($user). You can wrap that up in another class, like UserFactory->Create($data) and it can return the (persisted) User. Or that class can be called Registration if you'd like.
Did I mention you should use Dependency Injection to handle all of these services (like the Mappers and others like Factories maybe)? Maybe just grab the DIC from Silex, called Pimple. Or implement a lightweight one yourself (it's not hard).
I hope this helps. It's a high-level overview of some things I've picked up from writing a lot of PHP and using Syfmony2/Silex. Good luck and glad to see PHP programmers like yourself actually trying to "do things right"! Please comment if I can elaborate anywhere. Hope this answer helps you out.
You should first begin by writing a class as a wrapper to your Database object, which would be more clean that a global variable (read about the Singleton Pattern if you don't know it, and there is a lot of examples of Singleton Database Wrapper on the web). You'll then have a better view of the architecture you should implement.
Best is to separate datas from transactions with the database, meaning that you can for example have two classes for your User ; one that will only send queries and fetch responses, and the other that will manage datas thanks to object's attributes and methods. Sometimes, there can be also some action that doesn't require to interact with the database, and that would be implemented in these classes too.
Last but not least, it can be a good idea to look a MVC frameworks and how they work (even if you don't want to use it) ; that would give you a good idea of how can be structured a web application, and how to implement these pattern for you in some way.
This is my current system for a framework that I'm making:
I create an object upon a request to access a non-existing property, that has the name of an existing class through the __get function defined in the Core class. The Core class extends every class.
So it works like this:
class Someclass extends Core
{
public function classmethod()
{
$this->otherclass->method();
}
}
This works exactly how I want it to work. However, I have no idea (after a lot of frustration) how to edit/create properties of the object, using this system.
So something like this would't work.
$this->view->somevar = "newvalue"; // this doesn't work.
I guess it has to do something with the __set function, but I failed to find out.
I received the following suggestions how to tackle this problem:
Dependency injection, Namespaces, Singleton pattern.
I would love to see how to implement what I'm trying to do using one of these patterns.
I have no idea which to choose in order to achieve my simple problem: Use objects in other classes, so i don't need to put anything into __construct's parameters or using global variables.
I am using __autoload.
I hope i can tackle this problem with your help.
First of all, the architecture you're attempting is extremly bad. Aparently you are using "magic" to create objects attached as properties to other objects. Which is bad, because if you use _get/_set, you will end up in problems sooner rather than later. Also extending from a common parent is a bad thing because it generates huge inheritance trees, and it allows most of the objects to have more than one responsability.
Before starting a framework, you might want to look over: SOLID
Now coming back to your question, if you use __get for getting a value, you can as well use __set for setting a value.
__construct method is there in order to allow you to initialize the object with all the data it needs in order to fulfill his sole purpose. Avoiding the __construct is kinda stupid, and defeats the purpose. You might want to pay attention to the D in SOLID in order to see what Dependency Inversion really is and to understand it.
Using __set loses completely the ability to typehint interfaces and so on. Therefore the code can become really buggy and ijcredibly hard to follow, since the flow is not so well defined, and the allocation is done in the back via magic. Also i can come up with 1 million other reason for which the architecture you are trying to use is wrong, but i will leave that for another time.
Ok, I couldn't insert the overview image, but I'm required to create a PHP app for my studies, it must allow student to register, and the administrator to edit course and student info.
We are not required to code it in an OOP style, but since its the best programming practice to code in OOP, why not learn OOP from the beginning.
I'm a beginner but I know the basics about OOP, classes, inheritance, setters and getters and all that cool lingo, but I'm struggling to decide which parts of this app should be objects, should I make course and student classes or add, edit and delete classes? Any advice on how to approach and visualize such a problem would be appreciated.
Very roughly: This is how I would do it:
Store your data in SQL or XML. You will need two SQL tables, one for Students and one for Courses. You can use one XML file containing all the data, or you can use two files (which I recommend).
Create a class called, for example, dataItem with a property like '$arr_fields' corresponding to a single data record (a single row in a SQL table, or an XML record).
The dataItem class should have the following methods (all public):
loadFromSQL() (or loadFromXML())
saveToSQL() (or saveToXML())
add(), edit() and delete()
a view() method using HTML
These methods are obviously used to read and write data between the SQL/XML data and $arr_fields of the class, and to display the data in $arr_fields. The keys of $arr_fields are the SQL column names (or XML tag or attribute names) for the specific SQL table.
Try not to call loadFromSQL() or saveToSQL() in your constructor or in any of the other methods which are used to modify only the class data. Keep these actions separate. EDIT: This is a personal preference which helps me to keep track of the state of my objects.
Create Student and Course classes that extends the dataItem class.
You can override methods, for instance the view() method, inside your extended classes if you need to.
Then you can call the methods in Students and Courses from an Admin object (like rcdmk suggested) or maybe from StudentFolder and CourseFolder classes whose view() method contains buttons for the actions that need to be performed. (Let StudentFolder and CourseFolder extend a Folder class that you create).
UPDATE:
For example: If your primary key in a SQL table is id, then dataItem's loadFromSQL($id, $tablename) should set $arr_fields so that its keys are the column names and it's values are the values from the row whose primary value is equal to $id.
In Students, you can then override loadFromSQL() as follows:
class Students extends dataItem {
// other attributes
public function loadFromSQL($id) {
parent::loadFromSQL($id, "Students");
}
}
EDIT: On reconsideration, it might be better to set $arr_fields["id"] = $id and also set $tablename with the constructor for dataItem - then you never have to override loadFromSQL() or specify parameters for it. loadFromSQL() should then load the record if it exists. saveToSQL() should save $arr_fields in SQL if $arr_fields["id"] is set and create a new record if it is not set. Anyway, you must find a consistent way of interacting with the data which works for you, these are just possibilities.
However, if you are not experienced with OOP and SQL or XML, you might be opening a can of worms for yourself and it might be better to just do your assignment using functions only and php arrays for your data. Unless you have some time to learn...
From a simple perspective:
Abstract the main objects as classes and use methods for actions of this objects:
Student (object) are deleted (action) by the Admin (object), so
Admin class will have a deleteStudent method, because Admin deletes Students.
Another aprouch is to concentrate all Student related actions in the Student class:
Student class will have a public delete method that Admin can use.
Anyone that think this in better ways of explanation can edit this wiki.
Think about which aspects of your system are actually objects, you know, something you can do something with. The methods are what you do to the objects. So, you're on the right track with course and student classes, and add, edit, and delete would be methods of those classes.
But don't get too bogged down with it. If it's not your core assignment objective, you could quickly get in over your head by trying to do everything exactly the right way. If you can formulate a clear way to get to where you need to go, then go for it, if it seems confusing, back off it a little and learn some more.
You say that you know the basis of OOP, however you ask whether you should create Course, Student classes OR Add, Delete, Edit classes. Well maybe there are other practices, but I guess the most popular one and the only I am aware of is to use nouns as classes and verbs as their methods. Hence, intuitively there is something wrong with class "Add" or "Edit". What I would have done if I were were, is to think of all "entities" that might be considered an object - like Student, Course, Lecturer, Class (Room) and depending on how advanced your model should be you can add more like Building etc. Then try to implement basic things like creating new student, registering for a course, associating teacher with a course etc. Once you have it in place and IT IS WORKING you might want to add advanced things, like inheritance. For example you might want to say, that both Teacher and Student are a Person so you might want to create such abstract class and use inheritance.