Monday, December 10, 2012

Zend Framework 2 (ZF2) - Creating View Helpers and a Custom Captcha

Greetings Programs,
The code in this post is available here https://github.com/jdellostritto/zf2tutorial.git. This project represents my starting point for learning zf2. Feel free to use as needed.

Like ZF1 the captcha image has more than one input that is rendered one after the other. Styling can be challenging with this kind of layout. In this blog I demonstrate how to create an extended captcha image and a new view helper. Before I begin you might want to be aware of how the view helper system works. Here is how I understand it.

The stock captcha image(Zend\Captcha\Image.php) in ZF2 uses a view helper (Zend\Form\View\Helper\Captcha\Image.php).

The catpcha image also ( Zend\Captcha\Image.php) has a function name called 'getHelperName'. This function gives the renderer the view helper to render the catpcha. 'getHelperName' happens to return 'captcha/image' or and instace of this guy (Zend\Form\View\Helper\Captcha\Image.php).

If you look (using debug) the phpRenderer instance has the helper class called captchaimage as an invokable (found in the PhpRenderer::__helpers invokablesClasses). This invokable is the view helper we mentioned above (Zend\Form\View\Helper\Captcha\Image.php). Makes sense right... you create the image and the renderer is all ready there for us. This is just the image. As you are aware you have to give the image to a form element...

When you create your Captcha form element (Zend\Form\Element\Captcha.php) you  give the captcha image (Zend\Captcha\Image - what we just talked about) to it. We know it's all set because the renderer is already loaded. Well it's not what we want.

The 'form' element captcha has it's own helper (Zend\Form\View\Helper\FormCaptcha.php). In the render function of this helper you will see that the captcha image (zend\catpcha\image) is grabbed from the ElementInterface(line 33) and then the helper name via 'getHelperName' (line 42). Finally we retrieve a class instance of the helper from an instance of PhpRenderer and we rendered  the output (line 52 and 53).

In order to keep our sanity we have to keep separate the 'form element and view helper' from the 'captcha image an it's helper'. We give the captcha image to the form element captcha who already has a linked helper. The form element captcha render function will pull the instance of the captcha image we gave it, find it's view helper, and render it. All we really need to do is jump in here and give the captcha image a new helper that renders's the way we want and to override the captcha image preventing it from getting the original helper

Clear as mud right!
For our code we have to look at three things.
1: The view helper ('zend\form\view\helper\captcha\image' line 61) for the captcha defines a pattern for output as %s%s%s which produces what we already are aware of. So first thing's first we want is our own custom view helper with our own pattern. So we create one in our application module

module\Application\src\Application\View\Helper\Form\Custom\Captcha\ViewHelperCaptcha.php
...
Our view helper class above is a duplicate of the  Zend\Form\View\Helper\Captcha\Image.php class with a few exceptions. The first is that it does not use the Zend\Captcha\Image as this class points at a view helper found at Zend\Form\View\Helper\Captcha\Image. Remember that the Zend\Captcha\Image has a function called getHelperNames which returns a hardcoded helper name 'captcah\image' so when the form renders the image it will get the wrong helper. So the last two things we need to do is give the phpRenderer our custom view helper and create a new captcha image that extends the original Zend\Captcha\Image and overrides the setHelperName giving the new helper we just created. Notice lastly that we have changed the pattern in our helper above to put div's around our captcha elements.

Next we add our class to the view helpers in the phpRenderer invokables classes. This is done in module.config.php

...
The next step is to create  a captcha image that returns the view helper we have created and added to the phpRenderer's invokables class. We don't want to redefine the entire Captcha image we just need it to point to our custom view helper. To do this we are going to create  our custom class called CustomCaptcha.php here:
module\Application\src\Application\View\Helper\Form\Custom\Captcha\CustomCaptcha.php

We are going to extend the real Zend\Captcha\Image and override the 'getHelperName' so that it returns our  helper 'viewhelpercaptcha'.

...
The last thing we need to do is make sure we are using our CustomCaptcha image in our form. So here is a snippet of code from our RegisterForm.php in our user module that uses our custom captcha image and it's custom view.
...

Inspecting your structure the image and inputs are now wrapped in divs.

This makes for a more orderly design.



Dr. Lora Baines: You know, Flynn has been thinking about breaking into the system ever since Dillinger canned him. And he had Group 7 access.

Tron 1982.

8 comments:

  1. Yeah! I waited so long for it. I tried to move my projects from beta3 to beta4 to beta5 and finally, I can move it to Zend Framework 2 steady.

    ReplyDelete
    Replies
    1. I am still in the process of moving over. Fighting one battle at a time. If I can help you with something don't hesitate to present a problem.

      Delete
  2. Brilliant Jim, your explanation really helped and it made so much sense by the time I implemented your solution. Thanks for sharing this!

    ReplyDelete
  3. I just read this post again and am going to attempt to clean it up a bit. Aidyl's comment above is very true. The best way to get a handle on this is to implement the solution and debug it so you can look at the phpRenderer instance.

    ReplyDelete
  4. hi......excellent................this is very useful.........the codes were really understandable.........................thanks for sharing......................

    kill by captcha

    ReplyDelete
  5. Hi,

    good information

    Web application development services will successfully change the execution of your online business So, hire our skilled Ecommerce website company to get customized applications for your business.

    Best Website Designing and Development Company
    "
    Ecommerce Website Development Company
    "
    Zend Framework

    ReplyDelete
  6. Great post. thank you for sharing such a great information about Zend Framework 2 with us.

    ReplyDelete