PHP PDO Tutorial Part 3 - Models & Refactoring - Full PHP 8 Tutorial
Вставка
- Опубліковано 8 лис 2024
- In this video, we are going to do a bit of refactoring & extract business logic into models.
SOME OF THE WAYS YOU CAN SUPPORT THE CHANNEL
👍 Smash the like button
🤝 Subscribe to the channel & turn the notifications on
💬 Post comments, any feedback is greatly appreciated
⭐ Become a Patreon: / programwithgio
THANK YOU!
LESSON 2.32
Course Outline - github.com/gge...
Course Playlist - • Learn PHP The Right Wa...
man these videos are so full and complete that I myself need to watch several times to get the whole ideas and tips , thanks
Glad you like them. Thank you
This PHP video series is extremely useful! I'm grateful for your work!
Happy to hear that, thank you
I really love and appreciate what you do bro. You taught so many things to us totally free. Love and respect!!!!
Happy to hear 💙
After Jeffrey Way, you are my next favourite teacher. I just love the way you teach, the modern contents. Thats too awesome.
Hope to see you cover so many things in this course which we get out of the box in the framework but do not know how it works behind the scenes.
Also hope that you implement some design patterns and also SOLID principles as a part of this course.
Once again thank you so much for these awesome contents. I have become your fan.
Thank you so much 🙏
same
i feel the same really
The best PHP course
I love when you say "but let's keep it simple" and there are over 7 php files and hundreds of rows of code 😇😆😆
I suppose that will be clearer for me once I have fully check the Laravel lessons. I like how you show a few different ways for something, even though I'm a little bit confused sometimes. Thanks again and we keep going!
Heh, sometimes thats as simple as it gets 😆. Being confused is ok, it becomes clearer with more time
Hi Gio, I think would be good if we could see the folder structure (like in the vscode) during the course, I personally feel a bit lost when u keep changing files, would be good to see the folder structure so we can stick with u just by looking to the folders and knowing exactly where you are and understand how are things being put together. Great vid as always and thanks for your hard work.
Thank you & thanks for the feedback. I think I fixed this a bit in latest videos, the reason I usually keep it closed is because it takes too much space making other things smaller but in later videos I try to zoom in on things.
Soooooo. I spent a good part of today going through this again. I don't think I would have to go back to as many videos as I initially thought. One of the concepts to I struggled to grasp the most was the "proxying" with the callback function. But then I made a typo with the lastInsertId() at the end of it all that caused an error that didn't allow the view to display(talk about blessing in disguise lol). That kept me for over an hour as I tried to figure it out. Surprisingly, solving the problem by reading the error info displayed and trying to trace it, really helped me to better understand it. Thanks a lot Gio. I'm learning
That's great to hear. Good job
Best course I've seen!
Thank you
The video i like the most in this course. ~1 days in ~23 minute
💙💙
this video is really heavy in usful information for me
the way you structure your work and connect things together
thank you SoOoOoO much Gio ❤
Happy to hear, thank you
Excellent lesson to round up chapter two.
Glad you enjoyed it, thank you
No one ever explains these things except you
thank you so much
How did you learn all this? What sources did you use?
Mainly documentation and experience
Nice refactor. Your refactored code is really like what I see from Laravel framework. Great job Gio!!!!!
Thank you 🙌
18:03 "placing the *Percentages" 😂
Your tutorials are incredibly informative! LIKE '100%'
Thank you for your dedication! :)
Oops 😂, god carried away there :D. Thank you 💙
A little bit more information in this video for me, thank you so much for masterpieces like this. I have really used Laravel using mvc but did not understand how they were creating. Thanks a lot Masterpiece Man.
Glad it was helpful, thank you 💙
Thanks for the great video Gio !
at 11:07 in the __get() method you can return empty array instead of null in the case of the key doesn't exist and then you can remove the unnecessary ?? when creating the DB instance.
That depends on how you want to handle the non existent values. I prefer null because I may want to have special handling when things are not set
The new thumbs are pretty awesome, really like it
Thanks 😊
Very satisfying video to see a whole refactoring. Look I've a suggestion, why don't you add this project into a github repo? Simply because It started to be quite big. Be clear, is a suggestion not a critique :) . Course wise I think you are one of the best I've seen throughout different programming language, and it seems the best for PHP really👌
Opps, I've just realize that in the next video you ll expose the repo :) Sorry about that. I wrote to soon .
No worries 👍
Why you are not fan of singleton pattern?
Btw, thank you so much for this amazing course. I wish I could support you more, but for now, all I can offer are my heartfelt words of appreciation.
Mostly because it is overused in practice & sometimes used in places where its not needed
Hello. Just wondering why you used late static binding when you set the value of "private static DB $db" to a new instance of DB class? I mean you could have just used self::$db = // instance of DB instead of static::$db = // instance of DB? Am i missing something? Great video btw. Thank you
Hello & thank you. Yes self would work just fine, you aren't missing anything. I initially had that property protected (not in recording).
Thank you, your video helped me a lot.
Glad to hear that
Ok, so I usually code alongside as I watch the videos. But I just watched this one straight and I was getting lost all over the place. It's not the lesson, the lesson is great!!!! It's my catching up that I'm worried about. I'll watch again but I need to get some air. Sai. I need to grasp why you did some of the things you did.... Infact, there are so many concepts you used that shows me that I need to go back to so many lessons to recall the features and link your application of them. Still a lot of hard work ahead. Maybe I'll take the day off php and return tomorrow. It's hard☹️. Thanks a whole lot Gio. Your lessons are too amazing
It's ok, take your time, no need to rush things through. Also don't worry too much about not remembering things, those kind of stuff you start to remember when you practice & write code. I don't remember every single thing, I start to remember it when I'm working on a project and come up with questions and google things and so on. Memorizing & remembering everything is not the goal.
@@ProgramWithGio "memorizing and remembering is not the goal" so true Gio. I was forgetting that. Thanks for extra tips on top of the amazing lessons you've prepared. Thank you Gio. God bless
Great lesson again Gio!
can you explain, why it is bad practice to use Superglobals inside methods?
It kind of introduces global state & makes your method depend on some value that you cant guarantee will be set or not. Passing it down as dependencies to classes via constructors or methods is the better way
@@ProgramWithGio I understand that global state is not good whenever it can be avoided. But as Superglobals ARE clear (php-built-in) global state (they are available from everywhere, right?), I wonder why avoiding the usage makes sense. For me it is exactly the same as if you declare a global var but you don't use it globally but pass it down. Yes the global var itself is already bad practice but if you don't use it globally it is even unneccessary bad practice, am I wrong?
In my brain it would make sense to instead of filling the $_ENV superglobal, to create a local array as this would be the non-global equivalent and pass it down. In other words why shall we create a superglobal when we do not make use of its functionality?
Please do not understand this as any critizism because I have the greatest respect for your knowledge, experiance and attitude - that is why I try to understand exactly the basics of your decisions. To keep this simpler: Please tell me, is this a principle of:
- readability (I know better what the child does, as I know what I pass down to it),
- security (I have limited access points to that global info),
- debuggability (If I mess something with the "foreign" global state then I can only mess it on that point in my code)?
- or just a common convention?
all of the above. Its more readable, less places to make security mistakes in, easier to debug & also kind of a common convention. If you are a solo dev, then it doesnt really matter, you are in full control and can make decisions. You know the codebase in & out and know when & where to use those superglobals. Once you are in a team, it becomes tricky. Because now you are assuming that everyone on your team also knows when & where to use them and you are assuming they know the codebase as good as you do. Those assumptions usually lead to more bad code down the road.
@@ProgramWithGio I understand your point. At least for superglobals (like in this case) that are built up manually. For PHP built-in superglobals I cannot think of a way that it 'hurts'. The foreign programmer should know what my code does, but why should he/she know what instruments the code uses? Is there a risk of manipulation of the built-in superglobals that would cause my code to fail? Even in that case I guess I would implement validation to ensure to throw exceptions if such unwanted manipulation occurred?
Thank you
💙
Useful as usual, but I'd like to know which font-family are you using? The object operator (->), and other characters seem to be nice, even though you seem to no longer using the same font in your recent videos. Thanks
Its the same font family, I just had font ligatures enabled, you can enable it in PHPStorm settings
@@ProgramWithGio I found it, it's called Fira Code, thanks again.
Thanks Gio for the awesome content.
I have one query, with PDO class we had an option to specify the data type of bounded params. However, now that we have abstracted the PDO functions/properties with the DB class how should we do that?
You can still use PDO::PARAM_STR, PARAM_INT, etc
@@ProgramWithGio Yes, these are still available but should we use these in our Model classes because this would expose the internal details of the DB class?
Thanks again for the prompt response.
@@gautamverma2224 yea it should be fine, don't overthink it. If you don't want to use pdo constants directly within your models then you could create your own constants and set them with pdo constants but it's overkill.
@@ProgramWithGio Got it. Thanks
nice!
what key you pressed to have auto space on all variables ?
Ctrl alt L, it formats the code based on your settings
In config class how is the magic get method working It's not accessing the db array still its passing values from the db array without accessing it.
And awesome video it is better than a premium course
Thank you. It is accessing the db array, its doing this->config[name] where name is the variable, so when db property is "magically" accessed that variable is set to db and then it pulls array from config.
Hey Gio, thank you for this awsome series. I only did not understand something, in 15:42 why did make the `Model` class abstract, couldn't you just make it a non abstract class then extend it as usual ?
Yes you could, I just didn't want the base model class to be instantiable on its own since it doesn't really have a meaning without it being extended. The child classes are what provide functionality.
@@ProgramWithGio That makes sense now, I understand thank you for your quick reply.
Also I submitted a PR about the exercise of section 2. Wish if you review it and give me some feedback when you get a chance.
@@raidboulahdid5006 will check it out
Hey Gio! Always awesome work! Sort question, cause currently i'm having the same issue to one of my projects. At 9:36 you are mentioning the use of interfaces. What would you do in this specific case? Cause I'm currently using a concrete Config class as well, but i don't like it :/ Thanks in advance!
Hey, thank you. It mainly depends on how you will be handling configs in your application. If you will have more than one source of configuration then interface is great because you can implement the interface in your regular Config class and then have other sources that implement the same interface.
@@ProgramWithGio Thanks a lot Gio! This answers my questions :) Much love!
@@gerasimos-dimitriostheotok7071 no problem 👍
Hi Gio, 20:39 "we can have the register method return user id and invoice id", is that mean the method returning two values? May I ask about the best practices for returning two values from a method, should it return in key-value array like ["user_id" => 1, "invoice_id" => 2] or how to make it cleaner? Thanks in advance!
Hello, yes you can return an array key value pair or object that would contain both properties.
This is great.. Love it
Glad you like it 🩵
Hi , for DBH class this function correct :
public function __call(string $name, array $arguments ){
return $this->pdo->$name(...$arguments);
}
Both versions work, my approach is not incorrect, it's just alternative.
@@ProgramWithGio ok thank u
It would be great if you build Query builder, and share your ideas, experiences in this code at 17:28, We would get a chance to learn from your experience even more :)
We cover doctrine query builder later on in the series 👍
Yes , but I was talking about custom one, that way you could share your experience and we could learn to build our own 😀
Great Gio
💙💙
Hey Gio, in the App.php file $db is a private static variable. Now I know it is unlikely that this file will be extended but isn't self::$db instead of static::$db much safer here? or we can also declare it as protected.
Yea static is used in case it's extended & changed to protected, but self would work as well. Not sure what you mean by it being safer but as it stands they pretty much do the same thing since there is no inheritance.
thanks dear, make php mvc tutorials also and make a project base php tutorials
You're welcome. Will keep that in mind, thank you
Hi, 14:10 can you please explain why we don't create any properties in User and Invoice classes and pass all the info directly to create method? Wouldn't it be better if we would accept them in the constructor and create properties there, so we could use them in multiple methods, instead of passing data them to every method? For example in 20:11 we wouldn't need to pass 2 arrays of information to register method? Maybe i don't understand something, but thank you for your answer in advance.
Yes that's one way to do it but then you would be using User as entity as well as model, User model would have a state. I didn't do it that way because we haven't covered entities yet
@@ProgramWithGio oh ok, thanks
@@aleksandrkanygin2672 you're welcome. You can think of the User model in this lesson as kind of like a repository of queries without any state
How did you learn this:) you are a natural code talent
Comes with practice & experience. Also note that I reherse most of the videos ahead of time, and mistakes are usually cut out unless the mistake is a good example in which case I leave it in.
@@ProgramWithGio I appreciate you leaving some of the mistakes in, and it is kinda fun to sometimes spot them a few seconds before you do ;)
@@godmansarah that is indeed a great feeling 🙂. I try to leave mistakes in that add some valuable info but I do cut out silly mistakes to keep lessons smooth & not too long
hey gio , how are u.
where can i find the code for this video and the other videos
Hey 👋. Some of the earlier videos don't have source code because it's mainly concepts that are covered. Later we work on project and it has source code, also some lessons in third section also have source code, links for those should be in description of the video
@@ProgramWithGio ok thanks, and good job 👌
Hi mate, I just wondering why we are using "private static DB $db;" can we use "private DB $db;" what is the advantage of static in this case
Hello. In this case we use static to be able to access the same instance globally. Later in the course we cover dependency injection & DI container. Dependency injection is the better way.
@@ProgramWithGio thanks mate. Legend.
in 12:39 you said if you make a new instance of the app class you would get a new db connection
why?? isn't the db variable the same ? because it is a static property, so it belongs to the class itself not to the objects ?
so, there is only 1 db variable shared across all instances, how would a new one be created ??
sorry for asking many questions, I am not yet good with statics
The static method returns a single instance no matter how many times you call it. But if you instantiate the DB class manually using new operator like new Db(...) Then it would result in a new instance & new connection. Watch part 1 & 2 of the PDO lessons, it's the previous 2 videos.
@@ProgramWithGio sorry for delay in understanding 😅
I cloned the repo and played with it a little bit, now it is all clear to me.
for some reason I missed that the static variable $db will persist its value (which was set in the App() constructor the first time we made an app instance)
thank you for replying❤
at 11:45 you are calling DB statically in the HomeController without passing any arguments
but in the constructor of DB we need the $config array
so, how is it possible that it works without the config??
how did the insert work without knowing the db host url, username, password, database name and table name ?
Did you watch part 1 & 2? This is part 3 of the PDO lesson. We set that up there. The DB method returns the instance already instantiated with proper configuration. Try to watch the earlier videos and you'll see how we set it up
@@ProgramWithGio apologies, its all clear now thanks ❤
3:35
Where were the reasons stated?
Singleton pattern was first mentioned in "Static Properties & Methods In Object Oriented PHP" video, at here ua-cam.com/video/6VVN-2SCx7Q/v-deo.html you say that there will be more about it later, but I'm not sure if it was mentioned again before this "Models & Refactoring" video.
No it hasn't been mentioned. In that video I was referring to dependency Injection which is the right way and was covered recently in third section. Might do singleton support for the DI container as a bonus video, we'll see
Hi, please how did you get access to the $invoice[ ] variable in the view/index.php?
We pass it to the view as a parameter
Hello Gio, thanks. I got the solution to the problem already. I wrongly typed the $invoice variable returned in the find method of the App\Modesl\Inovoice class
I am equally very happy and grateful for your work Gio😍. Thanks a lot!!😊
I am getting Typed static property App\App::$db must not be accessed before initialization
Set the property to nullable and assign default null
why do you use these symbols () around for example (new App()) or (new SignUp()) ? you dont do it with all classes
You mean parenthesis? () Around it allows you to call the method right away, so (new SignUp())->method() where without it you would have to create variable first
$db->commit() inside try/catch? This must be after try/catch.
Why??
Ekhm... I always thought that commit() approved the changes made (adding, updates, ...), and since we check the capture of a possible exception, we only approve the changes. Browsing the internet, I see that I was wrong. As I understand commit() pre-approves, and if the exception occurs in Try/Catch, then rollback() cancels the changes made. My English is not very perfect.
@@JACKoPL Yup, commit should be within try/catch so that if something goes wrong it properly rolls back the changes.
Hello sir, i have a problem in database insert. I have main four columns keyCategory (1 category), Subcategories (could have 1-5 subcategories for each category) , then i have two main columns waterCooled and airCooled. The problem is that waterCooled and AirCooled itself have got 1-7 coulmns itself...and i have got 8 systems...some have 2 columns data others 7...in short the columns range from 1-7 in waterCooled and AirCooled... Categories and subcategories would remain same in every system ...please help me, how would i design db table and make a template so that admin can post systems in future
Hello. I am not sure I understand the problem. Can you show me what you've tried like table diagrams or schema and I'll try to help
@@ProgramWithGio where can i send the diagram or file...plz help me out 🙏🙏
@@techjavaid6177 Twitter or my email. You can find my email on the channel page under About tab
I don't understand why you created a new SignUp model instead of adding a signup method to the User model. 20:49
You could add it to User model, but then your user model will become bloated if you put everything there. That's why I created a separate model that deals with sign up. Less responsibility a class has the better it is
Next create php framework based on PSR
Not in my plans to create an entire framework but we'll cover bits & pieces so that its easier to understand when you move on to the frameworks like Laravel/Symfony
hy, first i want to thank you this tutorial is great, i have a problem in 11:50 when i want to test it shows me this error
Fatal error: Uncaught Error: Call to a member function execute() on null
i checked for my database connection and it's ok, any help please, thank you again
It means that your statement is null, if you show me screenshot of your code I can help troubleshoot it but error message is pretty clear that it's trying to call execute on null
@@ProgramWithGio thank you very much those are screenshot of the classes
drive.google.com/drive/folders/1fZOhLILIQvdXnwRjTb49Jf9UBnhXRJyW?usp=share_link
thank you agin
@@mohamedmennour2188 it says access denied. Can you DM me on Twitter and send me screenshots there?
@@ProgramWithGio would you try again please, i make it public , it s my fault, sorry
@@mohamedmennour2188 looks like your prepare returns false, on which line is the exception thrown for
not working App::db() returns nothing. no PDO functions like prepare execute are working on it. error showing is Uncaught Error: Call to a member function prepare() on null
Can you share a screenshot of your App.php? Also what version of PHP are you running?
@@ProgramWithGio I'm trying to reply but it's not going
@@ProgramWithGio my PHP version is 8.0.7 and here is the App.php (in my project named as DB.php) code class DB
{
private static Database $db;
public function __construct()
{
static::$db = new Database();
}
public static function initiate(): Database {
return static::$db;
}
and here is my test code in a controller
$db = DB::initiate();
$db = $db->prepare("SELECT * FROM auth");
echo $db->execute();
exit();
and the error is Uncaught Error: Typed static property DB::$db must not be accessed before initialization
@@dhrubajyotisen9392 constructor gets called when you instantiate the class. You are not instantiating the class you are calling a static method. You need to instantiate the class somewhere first. That's why you are getting that exception because you are trying to access a property that hasn't been initialized yet. Also why do you have two DB classes? One is DB and other is Database, you should just need one and other should be your App class
@@ProgramWithGio Oh very sorry! actually, I feel too drowsy for fighting with the issue maybe that's why I have missed the index.php file in your demo. I have an App class that handles the views, controller loading and wanted to keep the database-related classes separate with names just for my remembering preference. Anyway thanks a lot 😍😍😍😍
The first thing I would do is write tests, then write the productive code, and only then refactor 😉
Yup that is the end goal & is a good strategy. Haven't covered testing yet so it wouldn't make sense to add it in this video. We'll cover testing in third section
That entire proxy/ call user function is an absolute hack. Not readable at all.
Then you probably wouldn't like Laravel or any modern frameworks
@@ProgramWithGio Seems to be the direction of modern php
Procedural php mysqli is King. You Fools made programing way to complicated.
Keep using what makes you productive buddy but don't call anyone else fool that uses something else, that just shows the type of person you are. Best of luck
Gio has more than 55K subscribers. Why do you call people fools? Gio is putting in his best effort and sharing his knowledge totally free. We must respect it. Be a nice person and do something better for the world.
Hi Gio, I have a nagging question that need to be answered. Everything works fine when i test with the php built-in server (php -S localhost:3000) but it crashes when i load index.php using xampp. I see in the course you are not using xampp, so how to resolve this?
Hey, hard to say without seeing the code or your XAMPP configuration. DM me on Twitter and I can help troubleshoot it. Send me screenshots of your folder structure & your vhost config file
Hi Gio, Been following but am kind of stock at the last stage of the lesson.
Am unable to display the $invoice on the index.php.
On the HomeController.php, I did var_dump($invoice) and am getting the query result like
array(3) { ["id"]=> int(78) ["amount"]=> string(8) "550.0000" ["full_name"]=> string(9) "John Mark" }.
Some how, this isn't displayed on the views/index.php. Here is the index.php.
Test
Invoice ID:
Invoice Amount:
User:
And the last part of the HomeController.php
$invoice = $invoiceModel->find($invoiceId); // Just to check the values
var_dump($invoice) . PHP_EOL ; //
return View::make('index', ['invoice' => $invoice]); // this line should be like the line below;
return View::make('index', ['invoice' => $invoiceModel->find($invoiceId) ]);
I understand, the value is been passed as a $params[] through the View.php make().
Thanks for the support.
Hey, is your index.php right under views directory? Can you add some debug before the if ! empty check to see if that view is being loaded?
@@ProgramWithGio Thanks. I want to believe the page is being loaded. Added H1 HTML at the beginning of the views/index.php. the Home Page, H1 HTML tag is working. Sure there is something I am missing.
@@ProgramWithGio But somehow, am getting the duplicate entry errors on the page
@@mimoh2000 DM me on Twitter & send me screenshots of your code if you can
I ran into the same issue $invoice was undefined in the index.php view file but when i used $this.params[invoice] array it worked...did you manage to solve the problem?
Where is the github repo?
I am getting an error that I find very strange
Fatal error: Uncaught Error: Class "App\DB" not found in /var/www/app/App.php:15 Stack trace: #0 /var/www/public/index.php(27): App\App->__construct(Object(App\Router), Array, Object(App\Config)) #1 {main} thrown in /var/www/app/App.php on line 15
running composer dump autoload -o gave
class App\DB located in ./app/Db.php does not comply with psr-4 autoloading standard. Skipping.
So that clued me into renaming the file from Db.php to DB.php
@@wusswuzz5818 Awesome, sorry just saw this comment, again youtube is for some reason skipping notifying me for some comments. Maybe because it includes error with slashes & it thinks its a spam. Either way, I'm glad you figured it out, good job