Best OOP approach for this simple PHP app? - php

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.

Related

How to query database from a OOP point-of-view

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).

OOP implementation doubts

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.

Where do SQL queries belong in a MVC project?

I have read a book about MVC last week and a general one about design patterns, but I'm still confused as to where SQL queries belong in my code: the model or in the controller?
Let's take a very simple example, where you have a /popular page that will print the 5 most popular stories on a website.
In your model, you would have a class for prepared staments, and a class for assisting in the creation of the SELECT query. In your view, you'd have the HTML elements that display the /popular page.
Where does the query "SELECT most popular stories LIMIT 5" belong to? Is that something a controller class should ask, taking query methods from the model and passing to the view, or should the query be declared instead on a model class related to the /popular page?
Is the distinction even relevant? Would placing that query on the controller or the model be both considered professional ways to build a MVC?
Thank you. It seems most people get stuck understanding what to place on controllers
Edit: thanks for help everyone. Unfortunately as a new account I can't upvote any helpful posts yet
Usually (based on my experiences with MVC frameworks) the model layer takes care of database-related stuff in MVC.
Consider following approach:
Create abstract class which covers all the DB operations (selects, updates, etc). Each table would be a PHP class extending such class. You can then define DB table name in for instance private field, constructor or depending on model name.
Each controller (or the single controller) would load desired model, and use its methods to fetch data as associative arrays or objects, delete the data, change it.
After all DB operations have been done, controller returns view and passes data as its parameters.
Note that models are great place to put all the validation rules, and some helper methods due to the fact that they can be easily tested in PHPUnit.

zend framework rowset of rows, all same class

I'd like to use the same class as a row class and a base class for getting results, but think I am doing it the wrong way...
Ie I need the same class to extend Zend_Db_Table_Row_Abstract and Zend_Db_Table_Abstract but think this is putting logic for two different things into the same class? (and extending two is impossible)..
For example, I think the base class should handle select queries etc, and the row class should handle updating etc. But I'd like to be able to go:
class Article extends BaseModel { //Set table name and some custom functions }
BaseModel { //Define custom functions for finding rows and updating }
Article::findAll() //This is table logic
Article::insert($data); //This is row login
What's the right way of doing this?
I think you are looking for the ActiveRecord pattern:
An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.
There is a proposal for a Zend_Db_ActiveRecord component, but it never left the "New" stage. There is a number of UseCases in the proposal though, which might give you some ideas how to implement that yourself. You might also be interested in using existing 3rd party solutions, like Propel or phpactiverecord
Please be aware that ActiveRecord is often misused and has a number of drawbacks due to the violation of separation of concerns due to the intermingling of db access and business logic in one class.
The right way of doing this is to have two classes - one for rows (some kind of a model) and for the table (some kind of mapper).
Why do you want to have them in one class? Isn't it the intention of classes to seperate stuff that doesn't belong together (directly)?
If you really want it to be in the same class, and a method getTable to the row-class and extend the row class to be an adapter to the table class (which I strongly dis-suggest of course :).

What does a Data Mapper typically look like?

I have a table called Cat, and an PHP class called Cat. Now I want to make a CatDataMapper class, so that Cat extends CatDataMapper.
I want that Data Mapper class to provide basic functionality for doing ORM, and for creating, editing and deleting Cat.
For that purpose, maybe someone who knows this pattern very well could give me some helpful advice? I feel it would be a little bit too simple to just provide some functions like update(), delete(), save().
I realize a Data Mapper has this problem: First you create the instance of Cat, then initialize all the variables like name, furColor, eyeColor, purrSound, meowSound, attendants, etc.. and after everything is set up, you call the save() function which is inherited from CatDataMapper. This was simple ;)
But now, the real problem: You query the database for cats and get back a plain boring result set with lots of cats data.
PDO features some ORM capability to create Cat instances. Lets say I use that, or lets even say I have a mapDataset() function that takes an associative array. However, as soon as I got my Cat object from a data set, I have redundant data. At the same time, twenty users could pick up the same cat data from the database and edit the cat object, i.e. rename the cat, and save() it, while another user still things about setting another furColor. When all of them save their edits, everything is messed up.
Err... ok, to keep this question really short: What's good practice here?
From DataMapper in PoEA
The Data Mapper is a layer of software
that separates the in-memory objects
from the database. Its responsibility
is to transfer data between the two
and also to isolate them from each
other. With Data Mapper the in-memory
objects needn't know even that there's
a database present; they need no SQL
interface code, and certainly no
knowledge of the database schema. (The
database schema is always ignorant of
the objects that use it.) Since it's a
form of Mapper (473), Data Mapper
itself is even unknown to the domain
layer.
Thus, a Cat should not extend CatDataMapper because that would create an is-a relationship and tie the Cat to the Persistence layer. If you want to be able to handle persistence from your Cats in this way, look into ActiveRecord or any of the other Data Source Architectural Patterns.
You usually use a DataMapper when using a Domain Model. A simple DataMapper would just map a database table to an equivalent in-memory class on a field-to-field basis. However, when the need for a DataMapper arises, you usually won't have such simple relationships. Tables will not map 1:1 to your objects. Instead multiple tables could form into one Object Aggregate and viceversa. Consequently, implementing just CRUD methods, can easily become quite a challenge.
Apart from that, it is one of the more complicated patterns (covers 15 pages in PoEA), often used in combination with the Repository pattern among others. Look into the related questions column on the right side of this page for similar questions.
As for your question about multiple users editing the same Cat, that's a common problem called Concurrency. One solution to that would be locking the row, while someone edits it. But like everything, this can lead to other issues.
If you rely on ORM's like Doctrine or Propel, the basic principle is to create a static class that would get the actual data from the database, (for instance Propel would create CatPeer), and the results retrieved by the Peer class would then be "hydrated" into Cat objects.
The hydration process is the process of converting a "plain boring" MySQL result set into nice objects having getters and setters.
So for a retrieve you'd use something like CatPeer::doSelect(). Then for a new object you'd first instantiate it (or retrieve and instance from the DB):
$cat = new Cat();
The insertion would be as simple as doing: $cat->save(); That'd be equivalent to an insert (or an update if the object already exists in the db... The ORM should know how to do the difference between new and existing objects by using, for instance, the presence ort absence of a primary key).
Implementing a Data Mapper is very hard in PHP < 5.3, since you cannot read/write protected/private fields. You have a few choices when loading and saving the objects:
Use some kind of workaround, like serializing the object, modifying it's string representation, and bringing it back with unserialize
Make all the fields public
Keep them private/protected, and write mutators/accessors for each of them
The first method has the possibility of breaking with a new release, and is very crude hack, the second one is considered a (very) bad practice.
The third option is also considered bad practice, since you should not provide getters/setters for all of your fields, only the ones that need it. Your model gets "damaged" from a pure DDD (domain driven design) perspective, since it contains methods that are only needed because of the persistence mechanism.
It also means that now you have to describe another mapping for the fields -> setter methods, next to the fields -> table columns.
PHP 5.3 introduces the ability to access/change all types of fields, by using reflection:
http://hu2.php.net/manual/en/reflectionproperty.setaccessible.php
With this, you can achieve a true data mapper, because the need to provide mutators for all of the fields has ceased.
PDO features some ORM capability to
create Cat instances. Lets say I use
that, or lets even say I have a
mapDataset() function that takes an
associative array. However, as soon as
I got my Cat object from a data set, I
have redundant data. At the same time,
twenty users could pick up the same
cat data from the database and edit
the cat object, i.e. rename the cat,
and save() it, while another user
still things about setting another
furColor. When all of them save their
edits, everything is messed up.
In order to keep track of the state of data typically and IdentityMap and/or a UnitOfWork would be used keep track of all teh different operations on mapped entities... and the end of the request cycle al the operations would then be performed.
keep the answer short:
You have an instance of Cat. (Maybe it extends CatDbMapper, or Cat3rdpartycatstoreMapper)
You call:
$cats = $cat_model->getBlueEyedCats();
//then you get an array of Cat objects, in the $cats array
Don't know what do you use, you might take a look at some php framework to the better understanding.

Categories