Okay guys.
So next up we are starting with another let's call it abstract concepts.
So we are still not really building a full fledged blog application.
I'm gonna first introduce a design pattern that's called dependency injection container.
Now whatever programming language you will be using in the future, you will most likely have to work
with some kind of a dependency injection containers.
So I think it's super relevant and it's just important to understand this concept.
So let me quickly explain this.
And after that we're gonna implement a simple Di container.
So dependency injection is a design pattern.
And in this design pattern objects receive their dependencies instead of creating them or fetching them
themselves.
What does it mean in a simpler language.
So let's consider that example that we have right here.
You've got a database class.
It needs to have a config.
So it needs to get the configuration of the database the database name ports whatever information you
might need about the database instead of the database class trying to fetch this information from a
file, this info is just passed to the database.
Typically it's just done through a constructor.
And then there is another class that is called container.
Or it might just be called application.
This is how it would be called in our case an app that is a dependency injection container.
That basically has a map of all those classes that are already created with all their dependencies.
And if you have, let's say a script command line interface script that needs to load the database schema.
That's something we have done previously in the previous project.
Now we will have.
Now we'd like to have a more generic approach to those CLI scripts and will have more of them as well.
And consider we need a database so we don't want to worry about how do we get the database.
Where do we get the configuration for the database from instead?
All we do is we tell the Di container that we need a database, and the container already has the database
object created with the proper configuration passed to it.
So we just get it right away.
And that's the whole concept.
You simplify your own life by instantiating some of the classes within this dependency injection container,
passing all the dependencies that classes need into them.
Whether this is a config that's an array or some objects, whatever is needed, and then you just get
things you need from this Di container.
So to summarize you just reduce the coupling between components.
So nothing is really tightly coupled because everything is orchestrated by this Di container.
Then the code is better organized and maintainable because classes are smaller and they only do a one
specific thing.
And the code is also better for testability.
So if you need to write any kind of automatic tests, it's easier to create them if the code is separated
this way.
Okay.
So without any more further ado, let's just get started and do those two things.
We want to have a centralized configuration.
And also we want to have this Da container.
And we will only create a let's call it boilerplate of this database class, because that's a topic
for some next videos to actually implement some basic database abstraction that will help us with the
typical tasks that we do with a database.
Let's get started.
So we're going to create this dependency injection container inside the car folder.
Let's call it app.
That's essentially a central repository of things in our app.
We can call it this way.
So the namespace here is core.
Well that's everything just core.
And the class will be called app.
Now Let's define the field inside which we're going to keep all the entries.
And that's just an associative array.
Let's call it container.
Initialize it with an empty array.
This doesn't have any constructor.
But we need a way to bind something to this container.
So if I want to create a database class I need to put it under a specific key.
That's why we need the static function that will be called bind with a key and value.
That can be anything.
That's why we're going to use mixed type for it.
And it's void doesn't return anything.
And we're just going to do static container.
This is how we can refer to static data or static methods.
And just under a given key, we're going to put a value.
So you might also say that that's a simple wrapper around an array.
But also then we need a way to get some specific entry from this container using a key.
And the value can be mixed can be different things.
So it's important to check if an entry exists because if the array key exists, would return false for
the given key inside the static container, which is our array.
Just gonna throw an exception.
And then we can say that no key.
Is bound in the container.
So that's also a good practice to add.
Use statements for exceptions even though they are globally available.
So in other cases where we can find the key we just return it.
This would be static container with a given key.
Now this implementation of a dependency injection container might look simple.
And it is simple.
But generally the concept of a dependency injection container can be vastly expanded and can have some
other features that will help you.
Like.
For example, in Symfony framework, dependency injection container has a feature called Autowiring
where classes are instantiated automatically and also all their dependencies are created and automatically
parsed.
This is super handy with bigger applications.
Okay, let's get back to our thing.
Okay.
At this point, we can close this container file.
And I think that this video is all about organizing our app.
That's why I think we need two more files.
So previously we have created a bootstrap PHP file which of which was kind of initializing the whole
project.
And now we need this as well.
So we can initialize all the command line scripts and also the server the same way.
And another file that we need is config php.
That would be the file that will store all of our app configuration.
So the config for an app of this size can just be an array.
Now I'm returning something from a file which is not a function.
There is no function here.
So later on you're going to see how can we require this config file and get whatever was returned from
this file.
So we are returning the whole app config.
It's going to have two categories the app.
And maybe another one can be database.
So having one simple config array is enough.
So let me add the app title.
That's my blog.
Whether we are in debug mode, let it be true for now.
The driver, let's say we are using SQLite and the path does a path to a file and this would be the
current directory plus the database folder.
Blog SQLite.
Now at this point you should create this database folder inside the root directory.
This is where we're going to keep the database.
So now we need to move some things from the index file into the bootstrap file.
First, let me just copy everything into the bootstrap file and let's remove things that we don't need
in here.
So we definitely don't need routing because this is an index specific thing.
Because index.php file is a so-called front controller, the bootstrap file instead needs to generically
initialize the app.
So for example it should have the config and config we're going to get by doing require ones using current
directory and using the config php file.
So notice how.
So notice how I am requiring the contents of this file into the variable, which should now contain
this array that is inside this config file.
Okay.
So we've got the config and autoloading configured.
Now inside this file we should instead remove this require once and instead require once.
The bootstrap file.
So we need to go up and select the bootstrap file.
So now all the app initialization code is in one place is in a bootstrap file.
Same thing we did in the previous project.
So now we can reuse this bootstrap for command line scripts.
Now at this point I should be able to.
VAR dump config and I should see an array.
So I've got 500 error which means there is a bug to fix.
So in this bootstrap file I need to remove this two dots because we no longer need to go up, as the
vendor folder is at the same level as the bootstrap file.
After saving the changes, this should be fine.
And now we've got this whole config array on the screen, which means nothing else than we were just
successful in loading it.
Okay guys, so I'd like us to take a short break at this point.
And next up, I'd like us to create a database class that will be a database abstraction.
And then we're going to wire everything together using our dependency injection container so that we're
gonna have a config inside database inside.
And then if you would need to access the database, you're gonna always do it through dependency injection
container that we've just created.
That way, all the features that our application offers would be easily accessible everywhere.
But that's for the next video.