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.

Thursday, December 6, 2012

Zend Framework 2 (ZF2) - JavaScript and CSS Helper Class

Greetings Programs,

In Zend Framework 1.0 I used a CSS and JavaScript loader. This allowed me load CSS and JavaScript based on an action and a controller. It also allowed me to load common CSS and JavaScript required for my headers, footers, and other common components that might be found on a page. I wanted to try and repeat this in ZF2. In this post I will walk through how I accomplished this.

I am currently learning ZF2 and am building from the skeleton application and from Rob Allen's album application. You can get my code from https://github.com/jdellostritto/zf2tutorial.git.

The factory loaders (CssLoader.php, and JsLoader.php) are based on the an example provide by Evan Coury.
http://blog.evan.pro/creating-a-simple-view-helper-in-zend-framework-2


First create your PHP helper files in this location:

/module/Application/src/Application/View/Helper/JsLoader.php
/module/Application/src/Application/View/Helper/CssLoader.php 


In this next step we need to do two things in the onBootstrap function of the Applicaiton/Module class (found in project at: /module/Application/Module.php). First we 'attach' or 'hook' to a MvcEvent called EVENT_ROUTE. Which as I understand it signifies the completion of the route creation. In the function we attach to the EVENT_ROUTE we are going to create two factories that will be accessible to our view. The goals is for us to be able to call our JsLoader and CssLoader classes from our layout.phtml file.
...
On to the helpers. We created two helpers earlier so it's time to fill these in. We extend the AbstractHelper which provides us the prototype functions to use.  We send three arguments to the loaders. The Request, PhpRenderer, and a RouteMatch. Our constructor must accept each of these and make them available. The invoke function then does the work. In this example all we have done in both the CssLoader and JsLoader is move the original skeleton code loading of headLink and headScript from layout.phtml into these two handy loaders.

...
...
...
The last step is to replace the original headLink and headScript in our layout.phtml file.
...
I am diving in to ZF2 and am putting together what I can from many sources. If this approach is flawed or there is a better way to do it please leave a comment.

Crom: Look. This... is all a mistake. I'm just a compound interest program. I work at a savings and loan! I can't play these video games!
Tron: 1982

Monday, December 3, 2012

Zend Framework 2 (ZF2) - Validate a Check Box

If you have a registration form with a terms and conditions check box you'll probably want to validate that it is checked. This can be accomplished by using the Digits Validator.

Start by defining your input as follows: ...

Notice that the checked_value = 1.
Notice also that the unchecked_value = 'no'.
Look at the Zend\Validator\Digits class and notice that it validates the following:
...

The check box will fail validation when it is 'unchecked' because it contains the alpha characters ('no'). So next we create our input filter for our terms check box and give the 'NOT_DIGITS' our custom message.
...

I am still a little bummed out that decorators are no longer used but am impressed with some of the new capability provided by ZF2.


Master Control Program:  You're in trouble, program. Why don't you make it easy on yourself. Who's your user? 

Tron 1982