Sorry, the question was too bad to have a proper answer, so now I edited:
The manual says:
PDO::FETCH_CLASS: Returns instances of the specified class, mapping the columns of each row to named properties in the class.
My doubt is if the class extends form another class that have more atributes, will be this atributes instantiated?
Sorry if I'm not clear with the question, I'm not English speaker. Thank you all.
A good question.
For PDO, a class hierarchy doesn't actually matter. What PDO is doing is simply taking columns from database and assigning them to class properties, regardless of the class definition or inheritance.
If a property doesn't exist, PDO will try to create it.
If there is a property for which there is no column to map - then PDO will leave it alone.
As simple as that. So, it should create anything you select from the database.
As of the particular code you had in your question before - you have to debug it. Look, to see if anything was fetched, you are using whatever method printNickName(). But there could be any error either with this method or any intermediate process. Let me suggest you to create just empty classes, fetch your data in them, and check the properties directly.
After you make sure that all the properties are properly set, you may try with your custom class definitions. To debug the returned data I'd suggest to use
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'User'));
You may learn other details of PDO class handling from my article, Fetching objects with PDO
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 am new to Laravel and Eloquent, so excuse me if this is a totally stupid question.
I have been looking at how to create a model at both the documentation here and also another tutorial here (in the Creating Models using Eloquent ORM section) and I've noticed that the actual fields of the table are never mentioned, unless there is something specific about them (like having a relationship with another table, or not requiring mass assignment, or if they need to be hidden from JSON output etc.)
Are these fields being omitted on purpose and PHP just adds them when it performs the query using PDO with FETCH_OBJ turned on?
If yes why is it that we do not explicitly put the fields in the model? Doesn't it help us to know what fields we have, and also IDEs such as PHPStorm to pop up the right auto-complete fields?
If they are actually required, what access level do they need to have?
Thanks.
Column names (fields) are not required in Eloquent models. As you pointed out, it is only necessary to define the functions which determine the relationships that a model has with others.
It isn't necessary to include them, because of the reason you mentioned (Laravel does a select * and then adds all of the returned rows to the model object as public properties). This is a process dubbed hydration and you can see exactly what is happening by digging into the Laravel source. Here's a summary of what happens:
You call (for example), Users::find(123);
Illuminate\Database\Eloquent\Model::find() calls Illuminate\Database\Eloquent\Builder::find()
find() constructs the SELECT * FROM users WHERE id = 123 query and then returns the first result by calling Illuminate\Database\Eloquent\Builder::first()
first() adds LIMIT 1 by calling Illuminate\Database\Query\Builder::take()
Then first() sets the columns to be retrieved (* by default) by calling Illuminate\Database\Eloquent\Builder::get().
get() returns an Illuminate\Database\Eloquent\Collection by using the return value of Illuminate\Database\Eloquent\Builder::getModels()
getModels() actually performs the query and then calls Illuminate\Database\Eloquent\Model::newFromBuilder() for each row returned
newFromBuilder() creates a new instance of the model and sets the columns (fields) by calling Illuminate\Database\Eloquent\Model::setRawAttributes()
I've omitted some unrelated things such as eager loading to simplify the process, but this is basically what happens for each query.
You make a good point that knowing the fields beforehand can be helpful for autocompletion. Because of the nature of setRawAttributes() it is perfectly OK to declare all column names (fields) in your model (just make sure they are public). The convention, though (and for you sanity), is to omit them. Such declarations should be left to migration files.
After further examination of the source, it is not ok to declare the fields beforehand. This is because the actual attribute values are stored in an $attributes property and then accessed by the magic method __get(). The trouble here is that by defining the properties beforehand, you will prevent __get() from being called when you access the fields. Therefore, this is not an option.
However, there are ways to hint to editors (like PhpStorm) about the existence of properties without explicitly defining them.
There is another way to make phpstorm to auto-complete column name and avoid warning.
/**
* #property string $title Title of article
*/
class Article extends Eloquent
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.
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.
how can I extend the MySQLi class to explain all SQL queries on a given page?
Thanks.
There are several ways to do this. Here is one:
To start, you can get an explanation by simply prepending "EXPLAIN " to the mysql statement. See http://dev.mysql.com/doc/refman/5.0/en/explain.html for details on Mysql's explain.
Knowing that Mysql invocation, the mysqli::query and mysqli::prepare methods both take their first parameter as the $query string (side note: just use the Reflection class in a quick test script to get the current method or construct prototypes. You'll find extending mysqli_result class is not actually possible, but that shouldn't be a problem here).
Knowing that,
Store the mysql query string used in the calling of your extended methods as a new property of your extended `mysqli` class
Pass on the parent method's return results as normal
Create a new custom method to call this string property with `explain ` prepended and run a new separate query on that using any parent method or generic Mysqli invocation. This new method will be called any time you need to output the query explanation in your html view