Wednesday, September 11, 2013

Using the ServiceManager as an Inversion of Control Container (Part 1)

Intro:

In Zend Framework 1, it was difficult to follow best practices when it came to writing testable code. Sure, you could make testable models, but once you need those models in a controller, what do you do? Zend Framework 2 makes it much easier. In this post, I'll cover the basics of injecting a model into a controller.

Motivation:

The main goal here is to be able to wire up and configure your application from the highest level possible. Constructor injection + inversion of control makes it easy to determine which classes are dependent on other classes, and swapping classes with mocks or stubs is a breeze.

Prerequisites:
Begin by creating a new Buildingmodule, with its directory structure, similar to creating the Album module in the Getting Started guide.

To create objects, first let's take a look at what we are trying to get away from.

    $building = new \Building\Model\Building();

This is bad. At least in a controller, or another model. No more new anything (except maybe Exceptions...), no more hard-coded class names. Dependencies don't belong at this level of the code. Zend Framework 2's ServiceManager allows you to programmatically configure your dependencies. You should already be at least vaguely familiar with higher level dependency configuration from the ZF2 Getting Started guide, as this is how the AlbumController is configured, though it does a lot of stuff behind the scenes.

    $sm = $this->getServiceLocator();
    $building  = $sm->get('Building');

This approach is better, but you still don't want to put this in the controller. You should avoid pulling in classes using the ServiceManager anywhere except factories. Put another way, in general, $sm->get() does not belong in a controller or model, but does belong in Module.php's factories array, which I'll demonstrate further down. A class full of objects created this way has a lot of "soft dependencies", which are difficult to document and keep track of. Instead, to 'inject' a dependency into a class, it should be a parameter in the construction. Let's start by creating the BuildingController with a Building model as a dependency, which we'll learn how to inject shortly. I usually store dependencies as instance variables during construction and access them when needed with 'getters'. In this example, we are still instantiating a new ViewModel from within the controller. We'll fix this in Part 2, where we learn how to use the ServiceManager to create objects with runtime dependencies (such as the $variables parameter in the ViewModel construction)

 
<?php
#module/Building/src/Building/Controller/BuildingController.php
namespace Building\Controller;

use Zend\Mvc\Controller\AbstractActionController;

class BuildingController extends AbstractActionController
{
    protected $_building;

    public function __construct($building)
    {
        $this->_building = $building;
    }

    protected function _getBuilding()
    {
        return $this->_building;
    }
    protected function _getViewModel($variables=null)
    {
        #we'll fix this later
        return new \Zend\View\Model\ViewModel($variables);
    }
    public function indexAction()
    {
        $building = $this->_getBuilding();
        $building->addLayer('blue');
        $building->addLayer('red');
        $viewModel = $this->_getViewModel(array('building'=>$building));
        return $viewModel;
    }
}

The Application's ServiceManager is responsible for creating services (the model and controller are both services). Internally, when tasked with creating a service with a particular name, Building\Controller\Building for example, it runs canCreate("Building\Controller\Building"), which checks all of your aggregated config arrays. One of the places it checks by default is the array returned by the method getControllerConfig() in Module.php, if it exists. This is where we can add the factory closure for the model that the controller needs access to.

    #module/Building/Module.php excerpt
    public function getControllerConfig()
    {
        return array('factories' => array(
            'Building\Controller\Building' => function ($sm)
            {
                $building = $sm->getServiceLocator()->get('Building');
                $controller = new Controller\BuildingController(
                    $building, $viewFactory);
                return $controller;
            }
        ));
    }

Creating controllers is actually handled by the ControllerManager, a (sub)subclass of the main ServiceManager, and $usePeeringServiceManagers is set to false, which is why we need $sm->getServiceLocator()->get() here instead of just $sm->get(); it needs to retrieve the main ServiceManager to have access to the rest of the application's services.

In this controller, the constructor triggers the instantiation of the Building model. The model isn't actually created until the controller's constructor runs, since it is not a model being passed in, but a factory. The factory is a closure, a function without a name which can be saved as a variable. The ServiceManager sets services as 'shared' by default, meaning that the first time it is referenced, it calls the closure creating the object, and every time after that it simply returns the already instantiated object.

It is important to note that if the name of controller configuration (in this case Building\Controller\Building) is listed here, it cannot be defined somewhere else as well. For example, if it is in the $config['controllers']['invokables'] section in your module.config.php, the ServiceManager will try to 'invoke' it, that is, construct it with no arguments, and will fail. If you are following along with your code, check if this is the case now, and fix it if necessary. I'll wait.

Let's create the Building model as a simple class with no dependencies for now.

 
<?php
#module/Building/src/Building/Model/Building.php
namespace Building\Model;

class Building
{
    protected $_bricks=array();

    public function addLayer($color)
    {
        $bricks = array($color, $color, $color);
        $this->_bricks[] = $bricks;
    }

    public function getBricks()
    {
        return $this->_bricks;
    }

}

Because there are no dependencies or other required constructor arguments, we can define Building\Model\Building as an invokable in Module.php. The getServiceConfig() method is one of the aggregated configs that the ServiceManager checks to see which services it can create, and you should recognize it from the Getting Started guide.

 
    #module/Building/Module.php excerpt
    public function getServiceConfig()
    {
        return array(
            'invokables'=>array(
                'Building'=>'Building\Model\Building',
            ),
        );
    }


ZF2 provides multiple ways of doing a lot of things. It is possible, for example, to separate the configuration into multiple files, which might be advisable once your wiring starts getting complicated. The factories can be their own classes which implement 'FactoryInterface' instead of closures defined in the config array.

But, we are done for now. Control has now been inverted. We are injecting a dependency (Building) into a controller using the ServiceManager, and all of our wiring and configuration is in one place, Module.php.

If you want to test it out now and get something running, read the rest of this post. Otherwise, check out Part 2 to learn how to inject a dependency where each instance needs to be distinct and have its own configuration, e.g. using a $model->findAll() or similar.

You'll need to create a view

 
<?php
#module/Buidling/view/building/building/index.phtml
?>
<table >
<?php
foreach ($this->building->getBricks() as $key=>$layer)
{
    echo '<tr>';
    foreach ($layer as $brick)
    {
        echo '<td style="text-align:center; border:1px solid black;'.
            ' background-color:' . $brick . ';">';
        echo $brick;
        echo '</td>';
    }
    echo '</tr>';
}
?>
</table>

And then be sure to set up a route to /building so it is accessible.
 
<?php
#module/Building/config/module.config.php
return array(
    'router' => array(
        'routes' => array(
            'building' => array(
                'type'    => 'segment',
                'options' => array(
                    'route'    => '/building[/:action]',
                    'constraints' => array(
                        'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                    ),
                    'defaults' => array(
                        'controller' => 'Building\Controller\Building',
                        'action'     => 'index',
                    ),
                ),
            ),
        ),
    ),
    'view_manager' => array(
        'template_path_stack' => array(
            'building' => __DIR__ . '/../view',
        ),
    ),
);

Don't forget the getConfig() and getAutoloaderConfig() methods in your Module.php.

    
    #module/Building/Module.php excerpt
    public function getAutoloaderConfig()
    {
        return array(
            'Zend\Loader\ClassMapAutoloader' => array(
                __DIR__ . '/autoload_classmap.php',
            ),
            'Zend\Loader\StandardAutoloader' => array(
                'namespaces' => array(
                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
                ),
            ),
        );
    }

    public function getConfig()
    {
        return include __DIR__ . '/config/module.config.php';
    }

Finally, just go to http://localhost/building, and you should see a simple empty page with the layers we added.
Check out https://github.com/rwilson04/zf2-dependency-injection/tree/part1 for the code.

Here's the link to Part 2 again.

Comments are welcome.

52 comments:

  1. Nicely explained!
    Keep up the good work :)

    ReplyDelete
    Replies
    1. Machine Learning Projects for Final Year machine learning projects for final year

      Deep Learning Projects assist final year students with improving your applied Deep Learning skills rapidly while allowing you to investigate an intriguing point. Furthermore, you can include Deep Learning projects for final year into your portfolio, making it simpler to get a vocation, discover cool profession openings, and Deep Learning Projects for Final Year even arrange a more significant compensation.

      Python Training in Chennai Project Centers in Chennai

      Delete
  2. Big thank you for this! It clarified me some things as I begin with ZF2.
    I'm running into part2 :)

    ReplyDelete
  3. Inversion boots, otherwise known as gravity boots, allow for complete, inverted suspension from a stabilized horizontal bar or inversion rack. gravity boots benefits

    ReplyDelete
  4. Great survey, I'm sure you're getting a great response. 192-168-i-i.com

    ReplyDelete
  5. A very awesome blog post. We are really grateful for your blog post. You will find a lot of approaches after visiting your post. impactor error fix

    ReplyDelete
  6. What is the best free AppStore for iOS. Try Tutuapp, the best app and game platform for iPhone.

    ReplyDelete
  7. At that point Body Champ IT8070 inversion therapy table is the thing that you have to purchase. This device certainly fathoms back issues that doctors and advisors have supported the thing. gravity boots vs inversion table

    ReplyDelete
  8. Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon. Big thanks for the useful info. hoverwatch coupon code

    ReplyDelete
  9. Great article Lot's of information to Read...Great Man Keep Posting and update to People..Thanks Social Media Management Strategies

    ReplyDelete
  10. Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon. Big thanks for the useful info. write for us tech blog

    ReplyDelete
  11. visite our site for more information
    Techia

    ReplyDelete
  12. I found your this post while searching for some related information on blog search...Its a good post..keep posting and update the information. vpn 추천

    ReplyDelete
  13. visite our sit for more information about us
    EZTV Proxy

    ReplyDelete
  14. There are a lot of blogs over the Internet. But I can surely say that your blog is amazing in all. It has all the qualities that a perfect blog should have. https://wifiextender.eu/

    ReplyDelete
  15. Hi here you can find every solution releated to the android for
    like. if you want to customize your android phone i will help you
    Moreandroidmist if you want to find best android app related to every field this
    website help you like you want to see businsess app education app etc.
    so please visit my site for android problem androidmist thank you

    ReplyDelete
  16. You made such an interesting piece to read, giving every subject enlightenment for us to gain knowledge. Thanks for sharing the such information with us to read this... algebra calculator online

    ReplyDelete
  17. Hi! This is my first comment here so I just wanted to give a quick shout out and say I genuinely enjoy reading your blog posts. Can you recommend any other Beauty Write For Us blogs that go over the same topics? Thanks a ton!

    ReplyDelete
  18. Thanks for your insight for your fantastic posting. I’m exhilarated I have taken the time to see this. It is not enough; I will visit your site every day. security cameras

    ReplyDelete
  19. Hi! This is my first comment here so I just wanted to give a quick shout out and say I genuinely enjoy reading your blog posts. Can you recommend any other Fashion Write For Us blogs that go over the same topics? Thanks a ton!
    Visit our blog too Fashion Write For Us

    ReplyDelete
  20. Use Assignment Helper administrations in the event that you don't discover anything to form your scholarly paper or schoolwork. Now and again, you can't focus on your investigations in view of being occupied with numerous exercises and discover hard to compose your assignment.

    ReplyDelete
  21. That's certainly a massive amount, isn't it! Now just think what would happen if owing to some system malfunction or any other issue, all this data gets lost. data science course syllabus

    ReplyDelete
  22. Nice Post...
    Optimize PC Performance With HP Support Assistant
    HP computer or laptop may sometime work slow. To enhance the computer speed, it is required to download and install HP Support Assistant application. It is the software used to optimize your PC and help improve its performance. In many HP computers and laptops, the application comes pre-installed for the better performance of the device. However, using HP Support Assistant is the easy way to keep your PC running smoothly without any interruption. If it is not installed in your HP computer device, contact us via helpline number. We will guide you properly and once you scan your PC using such application, it will help maintain your system.

    ReplyDelete
  23. I’m Facing Issues With My Microsoft Office Setup
    Not able to finish office setup? It can be an issue with your System or installation procedure. Make sure the device on which you are trying to install office is compatible with your version of Microsoft Office. You can check the minimum system requirements for your Office product on the Microsoft office.com official website. Also, check if you have enough storage on your hard disk to install the Office suite. It can also be an issue with your internet. Try switching to another internet or using WiFi for a better experience.
    Sometimes when you are installing Office, you get an error. To fix the error, you can click on the Learn More option available on the page where the error has occurred. There you will find information about how you can troubleshoot this error.
    office.com/setup
    www.office.com/setup

    ReplyDelete
  24. There are alot of blogs over the internet but i can surely say that your blog is nice in all timemobiles price in pakistan

    ReplyDelete
  25. This is a very nice post. Thanks for sharing it.
    oral steroid tablets

    ReplyDelete
  26. A password plays a pivotal role in keeping security for a mail account. No matter whether we set up a simple password or complex one, we habitually tend to forget it. In addition to this, the same goes for Comcast users who often forget the password and seek a way to comcast email password reset. Besides, if those users who want to regain access to their Comcast account, there are some ways.

    ReplyDelete
  27. Looking for Homework Help In The USA? I recommend that you should try our academic writing services which you will never regret trying, we offer writing services under all niches and streams within your budget.

    ReplyDelete
  28. It explains that it does lead to negative impacts by leading to a shift on the preferences of spending funds. buy personal statement online

    ReplyDelete
  29. Try multiple variant of hashtags such as brand specific hashtags, general hashtags, and trending hashtags, to get noticed in searches. check this link right here now

    ReplyDelete
  30. I admire this article for the well-researched content and excellent wording. I got so involved in this material that I couldn’t stop reading. I am impressed with your work and skill. Thank you so much. learn more

    ReplyDelete
  31. If your account is public (as is by default), anyone can see your Boost Twitter Visibility, irrespective of whether they are following you. No, they can not see your tweets in the news feed. They can only see your tweet if they go to your page and read down through your tweets.

    ReplyDelete
  32. When students want to receive cheap assignment help australia they don’t want to risk their money and their reputation in college. Thus, unlike some of the other companies out there, our online assignment writing service guarantees that every paper is written from scratch and is 100% original. Whenever you order from Assignmentworkhelp, you are guaranteed to receive only original college assignments, done by professionals and done exclusively for you.
    cheap assignment help

    ReplyDelete
  33. HP Wireless Printer Setup

    Connecting a printer over a USB cable is pretty easy. But connecting a wireless printer can become very challenging quite often. Follow the HP wireless printer setup process to install it in no time.

    1. Take the printer out of the box and remove all tapes from it before starting.
    2. Plug in the power cord, turn on the printer and install the print cartridges. Allow your printer to complete its startup routine, which includes printing of an alignment page (if applicable).
    3. Go to the manufacturer's website and download drivers for your printer model.
    4. Install the drivers and follow the instructions during hp wireless printer setup process.
    5. In the meantime, go to printer's control panel and use wireless printer setup wizard.
    6. Identify your wifi network and connect the printer to it using its correct credential.
    7. Complete the wireless printer setup process by connecting to your printer model as it would appear during installation.

    hp wireless printer setup

    ReplyDelete
  34. Canon printer support phone number

    Canon wireless printer setup is very easy if compared with other available printers in the market. In case of any problem or confusion, canon printer support phone number is easy to get from the supplied manual. Follow canon printer setup process to install canon wireless printer.

    1. Take the printer out of the box and remove all tapes from it before starting.
    2. Plug in the power cord, turn on the printer and install the print cartridges. Allow your printer to complete its startup routine, which includes printing of an alignment page (if applicable).
    3. Go to the manufacturer's website and download drivers for your printer model.
    4. Install the drivers and follow the instructions during canon wireless printer setup process.
    5. In the meantime, go to priter's control panel and use wireless printer setup wizard.
    6. Identify your wifi network and connect the printer to it using its correct credential.
    7. Complete the wireless printer setup process by connecting to your printer model as it would appear during installation.

    canon printer support number

    ReplyDelete
  35. Brother Printer Setup

    We are one of the most reliable, and independent 3rd party printer technical support and service providers, providing 24/7 online or on-call technical support services to the users of brother printer at a very nominal charge. Our printer experts have extensive knowledge to set up brother wireless printer in the simple ways. For brother printer setup, you can call our Brother printer support experts 24/7.

    Brother Printer Support

    ReplyDelete
  36. Pogo games not loading

    Check for correct User Name or Screen Name. Most of the time we rely on the browser’s auto-complete feature and select wrongly entered screen name in the past.
    Passwords are case sensitive. Therefore, always check the letter’s cases of the entered password. If possible, type the password as you use in a notepad and then copy and paste the letters in the password field. Below is a list of things you should always check before entering into troubleshooting.
    1. If any of your family member shares the same account, ask them if they might have changed the screen name or password.
    2. Look into your email inbox to get the actual screen name when you had registered with Pogo
    3. If you find any point relevant to your case, you can go to the article explaining how to reset password of your Pogo account and follow all the steps carefully to reset your pogo account password.

    pogo.com/sign in problems

    ReplyDelete
  37. Gmail not working

    When your email stops working or gets hacked, don’t panic. Call Email Support Phone Number and let the highly skilled Specialists get you up running.
    Troubleshooting steps you can try to fix basic email problems:
    1: Make sure you’re connected to the web.
    2: Close the app, then reopen it.
    3: Sign out, then sign back in.
    4: Clearing the cookies and history of browser
    5: Check your browser extensions or applications and remove unwanted extensions

    Gmail not receiving email

    ReplyDelete
  38. Excellent write up, never seen such a amazing, well structured and informative content on the web. Keep sharing. But if you want to read such kind of informative articles or access huge academic database, login at research proposal writing service rendered by SourceEsssay

    ReplyDelete
  39. Thanks for sharing this article. I also work in the same area and provide Assignment Help to students for various subjects. Most of my students are from parts of the UK, USA, India, and Singapore. Our team of professors is from reputed Colleges. Visit our website to know our areas of expertise and let us know if we can be of help.

    ReplyDelete
  40. I am searching for the this topic info many year and trust me. My need fulfill after reading your this post. Happy to be learning random ideas and knowledge from here about each subject. I am also content writer but i cant write like this information, If you no any problem. Can you suggest me. I felt like an expert in this field. I have several articles on these topics posted on my site. Thanks buy assignment online - accounting assignment help - statistics assignment help

    ReplyDelete
  41. Astrologyswami.com is the official website of Aghori Tantrik Jitesh Bhai Ji. Tantrik Ji is the well known personality today who is guiding people for their better life. Vashikaran specialist near me | Vashikaran Specialist |Vashikaran Specialist Aghori Baba | Vashikaran Specialist in Tamil Nadu

    ReplyDelete
  42. Somatropin is the generic name of the drug sold under the brand name Ototropin.Various brands of this medication are used for the treatment of one of the following medical conditions: growth failure, growth hormone deficiency. Buy somatropin injection from official website Mediseller.

    ReplyDelete
  43. Thanks for sharing the informative content! We provide you the best solutions to your rr.com Email Login issue and other roadrunner email services issue. So if you are facing any email login issues, you can definitely come to us. On our website, you’ll find the solutions for Roadrunner, TWC, and Spectrum email.

    ReplyDelete
  44. SA 8000 is a social accountability management system standard that helps an organization to apply and develop socially accountable practices in the workplace. This voluntary standard is developed based on the ISO standard’s requirements and the guidelines of national labour laws, the UN Declaration of Human Rights, and international human rights norms. SA 8000 Certification in Hong Kong | Social accountability | Focused on employee welfare | covers legal requirements | Contact: enquiry@iascertification.com. Call @ +6531591803

    ReplyDelete
  45. Wow post!! I become speechless to see what I find in this post. In terms of knowledge, I have achieved something different but respective as per the academic knowledge domain. With the addition of the Online Assignment Help, you cannot depress what happens in your academic content domain. Now, you can do something better in your professional.

    ReplyDelete
  46. Wow! It is a completely different topic. Great choice of Topic! You can apply for a Turkey visa online. You can get your Turkey Visa in just 1 hour by selecting the express processing type. It only takes 5 minutes to apply for an electronic visa Turkey. Apply Online.

    ReplyDelete