Symfony2: Writing a Dependency Injection Extension Configuration

In this post I will look at how to write a more sophisticated Dependency Injection Extension for your Symfony2 bundles.

Bundle Level Config

The class looked like this:

<?php  
namespace LimeThinking\SpringBundle\DependencyInjection;

use Symfony\Component\HttpKernel\DependencyInjection\Extension;  
use Symfony\Component\DependencyInjection\ContainerBuilder;  
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;  
use Symfony\Component\Config\FileLocator;

class LimeThinkingSpringExtension extends Extension  
{

    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new XmlFileLoader(
            $container,
            new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.xml');
    }

    public function getAlias()
    {
        return 'lime_thinking_spring';
    }


}
?>

This loads a single service config XML file. You are not tied to using XML for this, YAML or PHP configuration can also be used and would be loaded as follows:

    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader(
            $container,
            new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.yml');
    }
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new PHPFileLoader(
            $container,
            new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.php');
    }

Doing any of the above will load the relevant service config into the Dependency Injection Container (or Service Container as it is also known). Whilst you can use YAML or PHP config files the best practice recommendation is to use XML for bundle service configuration if the bundle is intended to be released as a third party bundle. Whilst YAML is good for simpler config files the verbosity of XML is actually an advantage when maintaining a more complicated one. Likewise the nature of the PHP config means it is more difficult to decipher, the choice is still your's though.

You are not limited to loading a single config file, this way you can split up complicated service definitions into manageable files. For any parameters or service definitions that appear in multiple files those loaded later will overwrite these values. You can also then only load the definitions needed for an app rather then everything. For example in the AsseticBundle only the filters specified in the app config will have their service definition loaded.

App level config

So far I have only looked at loading config kept within the bundle. You can open up parameters to be set from an app's config file. Any config parameters relating to the bundle from the app's config will be passed into the load method of our extension as the $configs argument. So if the app's config.yml file contained the following settings:
lime_thinking_spring:  
    loader_class:   LimeThinking\SpringBundle\Asset\Loader\XMLLoader
    loader_method:  load
    filters:
         filterOne: LimeThinking\SpringBundle\Filters\FilterOne
         filterTwo: LimeThinking\SpringBundle\Filters\FilterTwo

then the passed in $configs array will be the following array
array(1) {  
  [0]=>
  array(3) {
    ["loader_class"]=>
    string(48) "LimeThinking\SpringBundle\Asset\Loader\XMLLoader"
    ["loader_method"]=>
    string(4) "load"
    ["filters"]=>
    array(2) {
      ["filterOne"]=>
      string(43) "LimeThinking\SpringBundle\Filters\FilterOne"
      ["filterTwo"]=>
      string(43) "LimeThinking\SpringBundle\Filters\FilterTwo"
    }
  }
}

It is nested in an array because you can have multiple config files, each will be placed into an array. So if you have also have settings in config_dev.yml:
lime_thinking_spring:  
    loader_class:   LimeThinking\SpringBundle\Asset\Loader\ArrayLoader
    loader_method:  get

Then the received configs array would like this:
array(2) {  
  [0]=>
  array(3) {
    ["loader_class"]=>
    string(48) "LimeThinking\SpringBundle\Asset\Loader\XMLLoader"
    ["loader_method"]=>
    string(4) "load"
    ["filters"]=>
    array(2) {
      ["filterOne"]=>
      string(43) "LimeThinking\SpringBundle\Filters\FilterOne"
      ["filterTwo"]=>
      string(43) "LimeThinking\SpringBundle\Filters\FilterTwo"
    }
  }
  [1]=>
  array(2) {
    ["loader_class"]=>
    string(50) "LimeThinking\SpringBundle\Asset\Loader\ArrayLoader"
    ["loader_method"]=>
    string(3) "get"
  }
}

You can then use these to set parameters in the Container in the following way:
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new XmlFileLoader(
            $container,
            new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.xml');

        $container->setParameter(
            'lime_thinking_spring.formulaloaderclass', 
            $configs[0]['loader_class']
        );
    }

Edit: Accessing the config variables in the above example does not deal with merging the values from different configs, it has effectively ignored the setting in config_dev.yml. Using the Config component as described below will avoid this problem.

Configuration Building

It is not however advisable to just set any values in the config to the DIC's service definitions. It would be much better to only set the values you want and to do some validation of the values passed in. Fortunately the pain of this is alleviated by using the built in Config component. We can build a configuration using its fluid interface which allows us to build up complex configurations specifying value types and more . Lets start with an example to show how to do this:

<?php

namespace LimeThinking\SpringBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;  
use Symfony\Component\Config\Definition\ConfigurationInterface;

class Configuration implements ConfigurationInterface  
{


    public function getConfigTreeBuilder()
    {
        $builder = new TreeBuilder();

        $builder->root('lime_thinking_spring')
            ->children()
                ->scalarNode('loader_class')
                    ->defaultValue('LimeThinking\SpringBundle\Asset\Loader\ArrayLoader')
                    ->end()
                ->scalarNode('loader_method')->defaultValue('fetch')->end()
                ->booleanNode('extra_value')->defaultValue(true)->end()
                ->arrayNode('filters')
                    ->children()
                        ->scalarNode('filterOne')->end()
                        ->scalarNode('filterTwo')->end()
                    ->end()
                ->end()
            ->end()
        ;
        return $builder;
    }
}

We can then use this to process the values passed in from the app's configs by adding to our Extension's load method:

<?php  
namespace LimeThinking\SpringBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Processor;  
use Symfony\Component\Config\FileLocator;  
use Symfony\Component\DependencyInjection\ContainerBuilder;  
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;  
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

class LimeThinkingSpringExtension extends Extension  
{

    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new XmlFileLoader(
            $container,
            new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.xml');

        $processor     = new Processor();
        $configuration = new Configuration();
        $config = $processor->processConfiguration($configuration, $configs);

        $container->setParameter(
            'lime_thinking_spring.formulaloaderclass', 
            $config['loader_class']
        );
        //--
    }

    //--


}
?>

The Processor will merge the values from $configs with the Configurtaion we have built checking the values as we go. In the above case we will end up with a a merged config that looks like this:

array(4) {  
  ["loader_class"]=>
  string(50) "LimeThinking\SpringBundle\Asset\Loader\ArrayLoader"
  ["loader_method"]=>
  string(3) "get"
  ["filters"]=>
  array(2) {
    ["filterOne"]=>
    string(43) "LimeThinking\SpringBundle\Filters\FilterOne"
    ["filterTwo"]=>
    string(43) "LimeThinking\SpringBundle\Filters\FilterTwo"
  }
  ["extra_value"]=>
  bool(true)
}

The Processor merges the values from the config tree with those from the app level config, if there are multiple app level configs then any repeated values are overwritten by those later in the array. The order they are in the array depends on which file imported which with those imported later appearing earlier in the array. Whilst this sounds counter intuitive it is what allows the values in config_dev.yml, which imports config.yml, to overwrite the ones in config.yml.

The Processor will not merge this config into the Service Container's config automatically but returns it as an array, you still need to choose which values from the config to write to the Service Container.

One thing to note is that when merging a configuration in this way is that an exception will be thrown if any values not specified are included in the app's config rather than them just being ignored.

Configuration Nodes

So let's look at the Configuration in some more details and look at some of the node types and their settings. The first thing to note is that the TreeBuilder uses a fluid interface so we can chain method class, each time you add a node you move to calling its methods, a call to the end() method moves you back up to the parent.

In the example above I used three types of node, scalar, boolean and array, so have a look at these and the other node types in a bit more detail:

Variable Node

variableNode() This is the most basic node type and does nothing to enforce the value of the node.

Scalar Node

scalarNode() A scalar node can be used for the following types: booleans, strings, null, integers, floats. Attempting to set something else to it, such as an array, will result in an exception being thrown.

Boolean Node

booleanNode() Whilst you can use a scalar node for boolean values using a boolean node will ensure that only boolean values can be set as an exception will be thrown for any other values.

Array Node

arrayNode() You can use an array node to allow nested config values in the app level configuration. In the above example I then explicitly set the children of the arrays type. Of course we do not always want to specify what every child of the array should be to allow some flexibility in the config. This means there is much more to using Array Nodes, howver I am not going to cover this here but will look at it in a future post. Edit: I have not covered this in a future post but it is not documented in the Symfony2 component documentation

Configuration Settings

Using the correct node type will provide us with some immediate checking of the value to ensure it is the correct type. Additionally further settings for each node can be made to further validate the config. Some of the settings we can use to enforce use are as follows.

Default Value

defaultValue($value) You can use this to set a default value for the node, if the node is then not given a value in the app level config the default value will be used. If no default value is given and the node is not given a value in the app level config then it will not appear in the processed config.

There are short cut methods available for setting the default value to true, false and null, these are respectively defaultTrue(), defaultFalse() and defaultNull()

Required

isRequired() You can specify that a node is required, if it is set and the node has no value set in the app level config an exception is thrown.

Allow Overwrite

cannotBeOverwritten() You can use this to say that the value of a node and its children cannot be overwritten. This does not mean that a default value is used and no value can be set in the app level config but that it can only have its value set in one app level config file.

Treat Like

treatTrueLike($value) This allows you to make your configuration easier for end users, by treating them setting true as something else in the background. For example if you had treatTrueLike('complicatedValue') then if the node is set to true in the user level config then it will be set to complicatedValue in the processed config. As well as treatTrueLike() there is treatFalseLike() and treatNullLike().

Entity Systems - Artemis-odb (Part2)

Artemis-odb is a high performance java based Entity-Component-System framework.
It is mature, actively maintained, and a continuation of the popular Artemis.

Highlights

Getting started

Community

Share your thoughts and questions with us!

Maven

<dependency>     <groupId>net.onedaybeard.artemis</groupId>     <artifactId>artemis-odb</artifactId>     <version>1.4.0</version> </dependency>

Gradle

  dependencies { compile "net.onedaybeard.artemis:artemis-odb:1.4.0" }

Manual Download

Entity Systems - Introduction (Part1)

What is an Entity System?

An entity system (also known as a Entity Component System) consists of three primary items:
  • Components
    • A component simply holds a piece of data and does not contain any game logic. Your typical component will have fields for primitive values and data objects.
  • Entities
    • An entity is a collection of components.
  • Systems
    • A system is typically an implementation that iteratively operates on a group of entities that share a specific set of components.

Can you give me an example?

Let's take a simple platform game where you have characters that move around. In this hypothetical example, you'll need ways of dealing with the character's game physics, drawing the character, and driving how the character moves. To build this, we could start with the following components:
  • Motion, for driving how the character moves
  • Spatial, for drawing how the character appears
  • Physics, for maintaining physical information about the character for collision handling, applying physical forces, etc.
  • PlayerInput, for defining player input
From this, we'd define a "player entity" and then add those components at run-time.
Next, we create systems to act on the various components. Our systems could be:

  • RenderSystem, which acts on any entities that contain Physics and Spatial components. We utilize the Physics component to determine where in the physics space the character is. We utilize the Spatial component to determine how to draw the character. If an entity does not have both of these components, then it will NOT be processed by RenderSystem.
  • MotionSystem, which acts on any entities that contain Physics and Motion components. We utilize the Motion component to determine what motion effects are applied to an entity (left, right, jump, etc.) We utilize the Physics component to apply forces to the entity based on Motion. As above, if an entity does not have both of these components, then it will not be processed by MotionSystem
  • PlayerInputSystem, which acts on any entities that contain Motion and PlayerInput components. The player input component could contain info about whether the related input is "locally" or "remotely" (via network or some other means) defined. For a "local" player entity, keypresses update the Motion component with information. For a "remote" player entity, network commands update the Motion component with information.
An example flow of this architecture would be: local player presses the "move left" key. PlayerInputSystem executes and detects the keypress, updating the Motion component. MotionSystem executes and "sees" the Motion for the entity is to the left, applying a Physics force to the left. The RenderSystem executes and reads the current position of the entity, and draws it according to the Spatial definition (which may include texture region / animation information).

Ugh. Seems like a lot of work. Why not use standard OOP?

One of the advantages of the Entity System is that it helps decompose or compartmentalize things. You have code that operates on very specific things and does this regardless of other components that the entity might have. Further, it helps prevent from things degenerating into the "blob" anti-pattern. As the game architecture becomes more complex, you simply add or remove components without having to worry about massive refactoring.
In a hierarchical approach, if two classes in very different places of the hierarchy tree require commonality, they'll either need to be derived from the same super class which takes on the shared qualities or copying and pasting will be required. This is fine for shallow trees, but games tend to evolve over time turning this into a potential chore.
Decomposing the architecture using an entity system gives us a very easy path for adding / extending / altering operation. Let's say in our example above, we now wanted to create some enemies. Rather than deriving or cutting and pasting things, we create a new component: EnemyAI. We then create a new entity that consists of:
  • Motion component
  • Physics component
  • Spatial component
  • EnemyAI component
...and we create a new "EnemyAISystem" that operates on any entity with the EnemyAI, Physics, and Motion components. This system implements enemy behaviors that define when and how to move the related entity, updating the Motion component in the process.

Our RenderSystem and MotionSystem will pick up new enemy entities with no further changes required.

Altplus Vietnam

From 2015 June - now

Job title : Senior Engineer

Viettel

From 2011 April - 2015 June

Developed and maintained ERP systems which is written entirely in JAVA on top of Oracle, Apache and Apache Tomcat. 
Develop Web application based on Struts 2, Spring, Hibernate and Dojo for client-side. Building and developing follow MVC pattern. Also work hard in web basic programing as HTML, JAVASCRIPT, AJAX
Then working as leader since 2013 and join analyzing, designing architecture, database.
Accomplishments
Developed and improved the digital document management for Office of the Government. Deployed and maintaining
● Developed and improved Organization and Personnel System, Criminal Records System and Digital Document Management for Ministry of Justice. Deployed and maintaining

  Trained new employees to get familiar with technologies and development methodologies usedby the company

Side projects

Storytree

Ho Chi Minh City — 2012 June - 2013 January

Developed in Android groups, building application named SimplePrint follow iOS version, connection with back-end via API written in PYTHON (Django). Application processing with Camera, Images, to create, manage custom views, then connecting server to upload and request printing. Also associate with Amazon W3, payment API (swipe), and social network API (Facebook, Twitter and  Foursquare).


IGT

Hanoi — 2009 February - 2012 May

Work as a Dev Leader. 
Developed and maintained a news aggregate site based on PHP.Designed and implemented a mobile client which interact with API server and SMS gateway based on J2ME platform.

How to setup Libgdx for Android Studio

What is Android Studio?
Android studio is an IDE for Android developers. First announced earlier 2013, it has since grown to be a very effective tool. Last month, June 2014, Android Studio has went from alpha to beta. If you wish not to use an ‘in progress’ IDE, your other option is Eclipse. But hey, out with the old and in with the new. Source: http://en.wikipedia.org/wiki/Android_Studio
Unlike Eclipse, Android Studio is, in my own opinion:
·       Faster
·       Responsive
·       Visually unified
·       More productive

What is libGDX?
I like to call it a convenience. It is like XNA game studios for Android developers. It integrates easily into Android Studio, is cross-platform, and is super-fast. For a full detailed list, visit their feature page http://libgdx.badlogicgames.com/features.html

How to correctly setup libGDX
It took me three days to figure this out. I am letting you do it in one day.
Go to the libGDX download page and download the setup app. This file will generate an Android Studio Project with all the necessary libgdx libraries and cross-platform modules for you. http://libgdx.badlogicgames.com/download.html
1.    This is only file you need to download.

2.    Click on the download file and save it to your computer.


Save this file to your computer
3.    Open the jar file. Then, fill in the dialog box as follows:
A.    Leave Name: unchanged
B.    Leave Package: unchanged.
C.   Leave GameClass: unchanged
D.   Go to your \AndroidStudioProjects Folder in the Library Explorer and create a new folder called \SetupGame. This is where our new project will be generated.
E.    Change Destination to:
                        i.          C:\Users\<USER_NAME>\AndroidStudioProjects\SetupGame
F.    Change AndroidSDK to:
                        i.         C:\Users\<USER_NAME>\AppData\Local\Android\android-studio\sdk
G.   Leave all Sub Projects: checked
H.   Uncheck the Box2d Extension unless you know you are going to use it.
I.      Click Generate:
Do not worry, it is not as complicated as it looks
4.   From the Android Studio welcome screen, click Import Project and select: C:\Users\<USER_NAME>\AndroidStudioProjects\SetupGame\build.gradld. This is going to open up the project for us.
Here you see the build.gradle file you need to import.
5.   DO NOT PANIC. You will get this screen saying there is an error. This is easy to fix
As you see, there is an incompatible version begin used.
6.   In your Library Explorer,
A.    Navigate to C:\Users\<USER_NAME>\AndroidStudioProjects\SetupGame.
B.    Right click on the .idea folder
C.   Delete It.
Simple isn’t it. Just delete the .idea folder.
7.   Back in Android Studio. Press (Ctrl+Alt+Y) to synchronize your project. A new .idea folder will be auto-generated with the correct contents. Honestly, I do not know why it does this. I just know that it works.
8.    Double tap on any of the file breadcrumb tabs to open up the project file viewer screen.
Doesn’t this look so clean. Anyway, this is what you will see on the left-hand side of the screen.
9.   Now open up your MySetupGame/build.gradle file and make one small change.
Change: classpath ‘com.android.tools.build:gradle:0.10+’ to …0.12+’
Yup, simply change that 0.10 to 0.12+
10. Sync your project again



If you do not get any errors, this is a success. you now have now setup libgdx for Android Studio.

Copyright © Am I a developer?. From Do Viet Kien.

Scroll to top