
In this article I want to talk again about the development of application architecture using Inversion of Dependence (
Inversion of Control ).
I already wrote on Habré about the
IoC library and about
Modular . Now I have gone even further and simplified everything that is possible and I will try to explain the principles of building architecture. And also talk about the new library
Granula .
Let's imagine that we want to make a library for managing users on the site. The first thing we need is a place where we will store information about
our users.
We describe the storage interface:
interface StorageInterface { public function set($key, $value); public function get($key); public function save(); public function load(); }
Great, now we need an implementation of this interface. To begin, we will store information in files. Create a class FileStorage.
FileStorage.php class FileStorage implements StorageInterface { private $file = 'data.json'; private $data = array(); public function set($key, $value) { $this->data[$key] = $value; } public function get($key) { return $this->data[$key]; } public function save() { file_put_contents($this->file, json_encode($this->data)); } public function load() { $this->data = json_decode(file_get_contents($this->file)); } }
Now create a user class
')
class User { public function __construct(StorageInterface $storage) { } }
Now to create an instance of the User class:
$user = new User(new FileStorage());
Well, what if some other programmer wants to use a database instead of files? To do this, it needs to create a DatabaseStorage class, implement a StorageInterface interface, and replace all occurrences of FileStorage. But changing the library promises problems with its updates.
To avoid this, let's enter options:
$options = array( 'StorageInterface' => 'FileStorage', ); $user = new User($option['StorageInterface']);
Now to replace FileStorage with DatabaseStorage, you just need to specify it in the options:
$options['StorageInterface'] = 'DatabaseStorage';
What we have now called options is actually an IoC container.
It is this architecture that allows you to build the most flexible applications and libraries.
In my previous article I talked about the Modular library, I continued to develop it, tried to simplify everything for the best understanding. Its main task is to learn how to use IoC in practice, creating a modular application architecture.
Now it is called
Granula .
Any library can be a module for a granule. For example, from a
Symfony Components component, you can create an MVC application similar to Symfony itself.
Each granule module must be described by its class:
use Granula\Module; use Inversion\Container; class MyModule extends Module { public function build(Container $container) {
For example, the description of the library that we created at the beginning of the article would be:
$container['StorageInterface'] = 'FileStorage';
You can even cut even more:
$container[] = 'FileStorage';
But in this case, the lazy loading of classes will not work, since FileStorage will be loaded by
Inversion (the IoC library of containers) right away to define its interfaces.
Sample module description for symfony Routing Component $container['request'] = $container['Symfony\Component\HttpFoundation\Request'] = new Factory('Symfony\Component\HttpFoundation\Request', 'createFromGlobals'); $container['Symfony\Component\Config\FileLocator'] = 'Symfony\Component\Config\FileLocator'; $container['Doctrine\Common\Annotations\Reader'] = 'Doctrine\Common\Annotations\AnnotationReader'; $container['Symfony\Component\Routing\Loader\AnnotationClassLoader'] = 'Granula\Router\AnnotatedRouteControllerLoader'; $container['Symfony\Component\Config\Loader\LoaderInterface'] = 'Symfony\Component\Routing\Loader\AnnotationDirectoryLoader'; $container['request.context'] = $container['Symfony\Component\Routing\RequestContext'] = new Service('Symfony\Component\Routing\RequestContext'); $container['router'] = $container['Symfony\Component\Routing\RouterInterface'] = new Factory('Granula\Router\RouterFactory');
Now you can create instances as in symfony using a container:
$object = $container->get('Class');
Or with the help of the factory (when using trait):
$user = User::create();
Then all the necessary modules are specified in Front Controller:
class App extends Granula\App { public function register() { return array( new MyModule(),
And in the index.php file run:
$app = new App(); $app->run();
I designed all the necessary modules to create a full-fledged MVC application. To play around with it, use
Composer to install:
composer create-project granula/app www
It includes:
- Symfony components
- Twig
- Doctrine orm
useful links
Contributors are Welcome!