DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Data Engineering
  3. Databases
  4. Using Select In Zend Framework 2

Using Select In Zend Framework 2

James Carr user avatar by
James Carr
·
Sep. 22, 12 · Interview
Like (0)
Save
Tweet
Share
11.23K Views

Join the DZone community and get the full member experience.

Join For Free

I’ve been using Zend Framework 2 on a recent project as a way to asses it’s features and one of the early blockers I had was trying to figure out how the heck to use the Select form element. As of this writing there is no good documentation on how to use it, so I’ll instead introduce how to use it in this blog post.

Album Manager, Revisited

For this demonstration I’ll be using the zend-skeleton application I originally worked on following through the zend framework 2 tutorial. I’ve left off from my previous post where we DRY’d up our code by using form annotations. You can follow me in this post by checking out my zend-skeleton project on github and checking out the “select-beginning” tag.

To start with, we have our annotated Album model object with just the title and artist:

<?php
// module/Album/src/Album/Model/Album.php:
namespace Album\Model;

use Zend\Form\Annotation as Form;

class Album{
    /**
* @Form\Required(false)
* @Form\Attributes({"type":"hidden"})
*/
    public $id;

    /**
* @Form\Required(true)
* @Form\Attributes({"type":"text"})
* @Form\Options({"label":"Artist"})
* @Form\Filter({"name":"StringTrim"})
* @Form\Validator({"name":"StringLength", "options":{"min":1, "max":100}})
*/
    public $artist;

    /**
* @Form\Required(true)
* @Form\Attributes({"type":"text"})
* @Form\Options({"label":"Title"})
* @Form\Filter({"name":"StringTrim"})
* @Form\Filter({"name":"StripTags"})
*/
    public $title;

So we’ve written our application and our customer is pleased, however he’d like to be able to tag the albums with a genre. When adding or editing a new album, there should be a genre drop down populated with options like Rap, Jazz, Alternative, Rock and Country.

Turns out this is a breeze, we just need to add a new field to our model and a Select form element:

 /**
* @Form\Type("Zend\Form\Element\Select")
* @Form\Options({"label":"Genre", "value_options":{
* "Rap":"Rap",
* "Jazz":"Jazz",
* "Alternative":"Alternative",
* "Rock":"Rock"
* }
* })
*/
    public $genre;

Now comes the boilerplate part, adding it to your views and AlbumTable (soon I’ll blog about replacing TableGateways). I’ll leave this as an exercise for the reader. See the tag select-annotated to see the completed work here. You’ll also need to add the genre column to the album table yourself (boo… no migrations).

Getting Values From an External Source

Commonly we’ll be getting genres from a database table or some other external source, not hard coded as a list of values in an annotation. To understand how to do this better, let’s first extract the value population out of the form annotation and do it elsewhere. The obvious place to manipulate the form after the fact is obviously not within the controller so let’s extract form creation out to something that can encapsulate it. With the lack of any kind of convention our guidance from the framework here, let’s just call it AlbumFormBuilder and go strong. :)

First we create a new class called FormBuilder under module/Album/src/Album/Form/FormBuilder. Previously (as in during the last tutorial) we applied extract method to extract a common method out of the addAction and editAction to handle the form building logic.

 private function form(){
      $builder = new AnnotationBuilder();
      $form = $builder->createForm(new Album());
      $form->add(array(
        'name' => 'submit',
        'attributes' => array(
            'type' => 'submit',
            'value' => 'Add',
            'id' => 'submitbutton',
        ),
      ));
      return $form;
    }

Now we simply need to move this method over to our new FormBuilder class and name it something meaningful, like “newForm”.

<?php
namespace Album\Form;

use Zend\Form\Annotation\AnnotationBuilder;
use Album\Model\Album;

class FormBuilder {
    public function newForm(){
        $builder = new AnnotationBuilder();
        $form = $builder->createForm(new Album());
        $form->add(array(
            'name' => 'submit',
            'attributes' => array(
            'type' => 'submit',
            'value' => 'Add',
            'id' => 'submitbutton',
            ),
        ));
        return $form;
    }

}

Now we could simply drop this object into the existing method in the AlbumController and see it still work (and I normally do this while refactoring). But to really harness the power we should create this new builder through ZF2′s factory mechanism. So we open up module/Album/Module.php and the following to the factories section:

public function getServiceConfig(){
        return array(
            'factories' => array(
                'Album\Model\AlbumTable' => function($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    $table = new AlbumTable($dbAdapter);
                    return $table;
                },
                // add this
                'Album\Form\FormBuilder' => function($sm){
                    return new \Album\Form\FormBuilder();
                }
            ),
        );
    }

And modify the AlbumController to use it via the service locator.

 private function form(){
        $sm = $this->getServiceLocator();
        return $sm->get('Album\Form\FormBuilder')->newForm();
    }

Now with the logic better encapsulated away from the controller, let’s simply set the value options directly within the builder class.

...
        $form = $builder->createForm(new Album());

        $form->get('genre')->setValueOptions(
            array(
                "Alternative",
                "Country",
                "Jazz",
                "Rap",
                "Rock"
            )
        );
   ...

Now if we save this and check out the app, we’ll notice that our new addition completely overrides what was in the annotation. Since we don’t need those anymore, we can remove the value_options attribute from our form annotation. Go ahead and edit or add a new album, select a genre and save it. Notice something? If you use an array of string literals the values will all be the index number of the item while the actual values will be the labels.

We have two options here… either specify keys that represent option values or explicitly define the label and the value (yes this is a bit strange). See the examples below for a quick reference.

/**
 * Generates the following:
 * <option value="alt">Alternative</option>
 * <option value="country">Country</option>
 * <option value="jazz">Jazz</option>
 * <option value="rap">Rap</option>
 * <option value="rock">Rock</option>
 */
array(
    'alt' => 'Alternative',
    'country' => 'Country',
    'jazz' => 'Jazz',
    'rap' => 'Rap',
    'rock' => 'Rock'
)

This actually didn’t give me what I originally expected… I expected to see the array keys as labels and the values as, well, values. However using a keyed array will basically match the same left to right layout an actual select elements option items will have. If you want to be more explicit you can also do the following:

array(
    array('value' => 'alt', 'label' => 'Alternative'),
    array('value' => 'country', 'label' => 'Country'),
    array('value' => 'jazz', 'label' => 'Jazz'),
    array('value' => 'rock', 'label' => 'Rock'),
)

Final Step: Extract Values Out

There was a reason I used ZF2′s dependency management to fetch the new FormBuilder instance and that was to easily extract the value options out to be provided by something else, perhaps another table gateway. So let’s go ahead and move that array to be returned by a new GenreTable.

<?php
// modules/Album/src/Album/Model/GenreTable.php
namespace Album\Model;


class GenreTable {
    public function fetchAllAsArray(){
        return array(
                'alt' => 'Alternative',
                'country' => 'Country',
                'jazz' => 'Jazz',
                'rap' => 'Rap',
                'rock' => 'Rock'
            );
    }
}

Now we modify FormBuilder to take the GenreTable as a constructor argument and use it to populate the value options.

class FormBuilder {
    private $genres;
    public function __construct($genres) {
        $this->genres = $genres;
    }
    public function newForm(){
        $builder = new AnnotationBuilder();
        $form = $builder->createForm(new Album());

        $form->get('genre')->setValueOptions(
            $this->genres->fetchAllAsArray()
        );
    ...
    }
}

Finally, we update module/Album/Module.php to inject an instance of the new GenreTable.

  'Album\Model\GenreTable' => function($sm){
                    return new \Album\Model\GenreTable();
                },
                'Album\Form\FormBuilder' => function($sm){
                    return new \Album\Form\FormBuilder(
                        $sm->get('Album\Model\GenreTable')
                    );
                }

Now we’re free to change the object injected into FormBuilder to fetch genres from the database rather than use an in-memory array when we’re ready but I’m tired of writing TableGateways. In my next post I’ll make my code a bit DRY’er by ripping those table gateways out in favor of doctrine. :)

You can see my completed work for this post on github.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Framework Database Form (document)

Published at DZone with permission of James Carr, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • An Introduction to Data Mesh
  • Stream Processing vs. Batch Processing: What to Know
  • What Is Policy-as-Code? An Introduction to Open Policy Agent
  • Agile Transformation With ChatGPT or McBoston?

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: