📜 ⬆️ ⬇️

Sectional Symfony2 Application

Watching open mouth for a virtuoso magician and his beautiful helpers, many, however, are focused on something else entirely: how does he do it? how is everything inside there?


The same thing happens when working with frameworks that do everything for us, but I want to know how they do it, and if necessary, be able to change their behavior. Unfortunately, the documentation, no matter how good it is ( and in Symfony 2 it is already quite good ), tells how to use all this “magic”, but does not reveal the whole point.

This article is an attempt to figure out how the application is initialized and what “Symfony2 Kernel” is.

For those who do not like big texts, a brief outline of the main components and a small description of the ongoing actions are immediately attached.

Brief description of the process



')
Clickable

1. All requests are accepted by the Front Controller (FrontController).
2. Configure class autoloading (autoload).
3. A kernel is created depending on the environment.
4. Runs the kernel.
1. Initialize the Bundle list.
2. A Dependency Injection Container is created.
1. A container is created with the main parameters.
2. Each bundle modifies (build) the container.
3. The application configuration is loaded.
4. The container is compiled.
1. Extensions are processed.
2. References to parameters are replaced by real values.
3. The container is placed in read-only mode (frozen).
3. Run the bundles.


Frontcontroller


As the front controller are the usual scripts. Examples include scripts from the standard Symfony2 distribution .

All these front controllers are built on the same principle:


Kernel


The kernel is a class that implements the KernelInterface interface, its task is to initialize the environment. The core of the kernel is based on two main components: the Dependency Injection container (the theory can be learned, for example, from Fowler ) and the bundle system. Bundle (bundle) - analogue plug-in from symfony 1.x. More information about the bundles can be found in the official documentation . Of course, besides the kernel interface itself, there is a standard abstract implementation of Kernel , which is mainly discussed further.
The initialization code looks something like this:
// init bundles $this->initializeBundles(); // init container $this->initializeContainer(); foreach ($this->getBundles() as $bundle) { $bundle->setContainer($this->container); $bundle->boot(); } 


Container initialization


The result of this step is a fully-ready read-only container. This process is divided into 4 sub-steps:
* In compiler theory, there is the concept of “passage”; here it is meant roughly the same thing, therefore CompilerPass translated it this way.

Modification of the container with bundles


As noted above, during the compilation process, each bundle has the ability to make modifications to the common container. The main modification method is to add compiler passes.

Compiler pass


At compile time, the container performs a series of passes to bring its contents to the final state. Passages are implementations of the CompilerPassInterface interface and come in 6 types (in order of execution): merge, beforeOptimization, optimization, beforeRemoving, removing, afterRemoving — the default configuration of the compiler already contains a set of passwords.

In CompilerPass bundles, it is most often used to process tags in a container . An example of a standard TwigBundle:
  $definition = $container->getDefinition('twig'); $calls = $definition->getMethodCalls(); $definition->setMethodCalls(array()); foreach ($container->findTaggedServiceIds('twig.extension') as $id => $attributes) { $definition->addMethodCall('addExtension', array(new Reference($id))); } $definition->setMethodCalls(array_merge($definition->getMethodCalls(), $calls)); 


Container extensions


The container is the central element of the system, in fact, it concentrates all the functionality of the application, respectively, to add any functionality, you need to put the necessary services and parameters in the container. For the convenience of such modifications, there are container extensions (which are processed by a special “merge” pass mentioned above).
Extensions is an implementation of the ExtensionInterface interface, and the abstract Extension class reduces routine actions and adds convenient methods. Extensions usually work as follows:

Extension configuration example ( app / config / config.yml ):
 # Twig Configuration twig: debug: %kernel.debug% strict_variables: %kernel.debug% 

This configuration says that you need to pass to the extension ( ExtensionInterface :: load () ) with the name twig ( ExtensionInterface :: getAlias ​​() ) the parameters defined in the corresponding section.

It is very simple to connect the bundle extension, you just need to create a class with the appropriate name ( DependencyInjection \ BundleNameExtension ) and the code of the Extension :: build () method will load the extension itself (the main thing is to remember to call the parent method and the heir;)).

Run the bundle


And the last stage is the launch of the bundles. In fact, most bundles do nothing at this stage; it is designed to perform actions that cannot be performed by the container. For example, the main Symfony2 bundle (FrameworkBundle) at this stage loads the class cache, mentioned more than once in this article.

Conclusion


At this point, the initialization process of the Symfony2 application can be considered complete: all the preparatory steps are completed, and the container contains all the necessary functionality. It remains to get the necessary service from the container and call its methods to execute the application.
The reader is probably concerned about a rather complicated and resource-intensive initialization process, but everything is not so bad. Symfony2, along with flexibility, does not forget about speed, so "out of the box" provides many optimization solutions. So, for example, the entire container creation process is cached by creating a class containing all the settings, and on the next call (if this is a debug mode) instead of loading a lot of configs of various parameters, running the container compiler, etc. the generated class will be just loaded and the finished container object is immediately created.

From the author


This completes the first dive into the wilds of symfony2. If this type of articles about Symfony2 is interesting for readers, then it is possible to turn it all into a series of articles with an analysis of the framework's internal parts, individual components and popular bundles. In addition, this is my first article, despite the long stay on Habré. I like to speak more than to write, but I try to cultivate in myself such a way of presenting my thoughts. Therefore, I would be very grateful for the feedback directly on the presentation of the material: how difficult it is perceived; what is better to do more emphasis on what is less; may need more illustrations and code examples; rely more on those who are familiar with the subject area, or try to describe, so that it is clear to all, etc.

Source: https://habr.com/ru/post/116834/


All Articles