Advertisements

Archive

Archive for March, 2008

Building table based forms in Zend_Form

March 24, 2008 11 comments

In web applications it is fairly common to want to edit multiple rows of the same kind of information, formatted into a table, kind of like you can in a spreadsheet. These forms are generally for editing existing information pulled from a database, which is usually already in an array format. Most of the examples I can think of at the moment need explanations of the context to make much sense, so I’ll pick an example that isn’t as likely to be useful but doesn’t need explanation.

Suppose I have a table in my database that lists contacts with title, first name, last name, and so on. When I fetch the data from the database, I’m likely to have an array that looks something like this:

$array[0]['id']    = 1005;
$array[0]['title'] = 'Mr.';
$array[0]['first'] = 'Ted';
$array[0]['last']  = 'Smith';
$array[1]['id']    = 1006;
$array[1]['title'] = 'Mr.';
$array[1]['first'] = 'Mark';
$array[1]['last']  = 'Jones';
$array[2]['id']    = 1007;
$array[2]['title'] = 'Ms.';
$array[2]['first'] = 'Sally';
$array[2]['last']  = 'Adams';

I want to get this into a form structured as a table, that submits the whole thing as one form. So that the posted results like this:

$contacts[1005]['title'] = 'Mr.';
$contacts[1005]['first'] = 'Ted';
$contacts[1005]['last'] = 'Smith';

I want the array to look like this because its much easier to handle the results than if we used the actual field name or id as the variable name.

I couldn’t find anything in the Zend Framework documentation, lists, or various tutorials that explained how to do this very clearly, so I thought I’d post at least one way to accomplish this in Zend Framework. This is based on 1.5. I’m going to start by showing the whole thing together. In practice it might not appear this way in the context of your controller class, but hopefully this is clear enough to understand how to apply it. After I show the whole thing I’ll walk through it and explain the pieces.

$form = new Zend_Form();
$form->setMethod('post')
     ->setAttrib('id', 'contactForm');
$subForm = new Zend_Form_SubForm();

foreach($array as $rownum => $row){
  $id = $row['id'];
  $rowForm = new Zend_Form_SubForm();
  foreach($row as $key => $value){
    if($key == 'id') continue;
    $rowForm->addElement(
      'text',
      $key,
      array(
        'value' => $value,
      )
    );
  }
  $rowForm->setElementDecorators(array(
    'ViewHelper',
    'Errors',
    array('HtmlTag', array('tag' => 'td')),
  ));
  $subForm->addSubForm($rowForm, $id);
}

$subForm->setSubFormDecorators(array(
  'FormElements',
  array('HtmlTag', array('tag'=>'tr')),
));

$form->addSubForm($subForm, 'contacts');

$form->setSubFormDecorators(array(
  'FormElements',
  array('HtmlTag', array('tag' => 'tbody')),
));

$form->setDecorators(array(
    'FormElements',
    array('HtmlTag', array('tag' => 'table')),
    'Form'
));

$form->addElement(
  'submit', 'submit', array('label' => 'Submit'));

$form->submit->setDecorators(array(
    array(
        'decorator' => 'ViewHelper',
        'options' => array('helper' => 'formSubmit')),
    array(
        'decorator' => array('td' => 'HtmlTag'),
        'options' => array('tag' => 'td', 'colspan' => 4)
        ),
    array(
        'decorator' => array('tr' => 'HtmlTag'),
        'options' => array('tag' => 'tr')),
));

As you can see, this approach uses subforms, which allows us to automatically build the array in the form, as well as having a convenient structure for applying decorators. In order to get the array right, we use two layers of subforms (subForm for $contacts, and rowForm to create each row of the table). I couldn’t figure out a good way to not do that and still get the array I wanted in the html. setElementsBelongTo doesn’t quite do the trick.

$form = new Zend_Form();
$form->setMethod('post')
     ->setAttrib('id', 'contactForm');
$subForm = new Zend_Form_SubForm();

This just sets up the form, tells the form it should post and have an id of ‘contactForm’. You might note that I didn’t set an action for the form. Zend_Form does set the action, but leaves the value blank. This conveniently posts the form back to our action (supposing all the browsers handle blank actions as specified in the relevant RFCs). The $subForm line just creates our first subForm for use later.

foreach($array as $rownum => $row){
  $id = $row['id'];
  $rowForm = new Zend_Form_SubForm();
  foreach($row as $key => $value){
    if($key == 'id') continue;
    $rowForm->addElement(
      'text',
      $key,
      array(
        'value' => $value,
      )
    );
  }
  $rowForm->setElementDecorators(array(
    'ViewHelper',
    'Errors',
    array('HtmlTag', array('tag' => 'td')),
  ));
  $subForm->addSubForm($rowForm, $id);
}

For each row in our data we create a subForm, which we populate with an element for each field in our data, setting the value for each to the value from our data. We decorate this subForm in the loop, wrapping each element in a td tag. Note that we don’t need to worry about the name of the element. We just set it to our data field name, and the framework’s subForm handling deals with the rest. Of course in practice your fields might not all be simple text fields, so the actual code would get more complicated but the process is the same. I also should mention that in practice you almost certainly want to check that $array is actually an array before you do this, or you’ll be looking at lots of warnings (at least) in your logs.

$subForm->setSubFormDecorators(array(
  'FormElements',
  array('HtmlTag', array('tag'=>'tr')),
));

$form->addSubForm($subForm, 'contacts');

$form->setSubFormDecorators(array(
  'FormElements',
  array('HtmlTag', array('tag' => 'tbody')),
));

Now that we have a rowForm for each data row added to our subForm, we can decorate each of these with a tr tag, and assign the whole thing back to the parent form. This is where we tell Zend_Form that the parent should be ‘contacts’, so that gets in our result array. Then we decorate the contacts subForm with the tbody tag to get it nicely fit into the table.

$form->setDecorators(array(
    'FormElements',
    array('HtmlTag', array('tag' => 'table')),
    'Form'
));

We need to decorate the whole form with a table tag. This likely needs a class and id, but we leave it plain in this example.

$form->addElement(
  'submit', 'submit', array('label' => 'Submit'));

$form->submit->setDecorators(array(
    array(
        'decorator' => 'ViewHelper',
        'options' => array('helper' => 'formSubmit')),
    array(
        'decorator' => array('td' => 'HtmlTag'),
        'options' => array('tag' => 'td', 'colspan' => 4)
        ),
    array(
        'decorator' => array('tr' => 'HtmlTag'),
        'options' => array('tag' => 'tr')),
));

Chances are we want a submit button, so here we add it to the bottom, and decorate it with its own row in the table.

The order of a surprising amount of this is arbitrary. You could set the table tag toward the top, for example, if it flows better for you. There are, of course, also completely different ways to do this. Several of the examples in the manual extend Zend_Form rather than do it the way that I have here. To me, this seems more clear.

[2010-02-06 I edited this slightly to fix some formatting issues introduced by a WordPress migration.  After almost two years this post still gets visits, and I figured maybe it should be readable.]

Advertisements
Categories: PHP Tags:

Agile thinking for distributed teams

March 11, 2008 2 comments

Recent work changes have led me to think more intensely about development methodologies, project management for small teams, and similar issues, and I’ve been reading more about Agile development. I am much more interested in the philosophical underpinnings, the values of Agile, the overall approach of Agile development, than I am in the specific practices that make up a particular “official” methodology such as XP or Scrum. So I was interested to see Brian Marick’s post on his Exploration Through Example blog entitled “What is Agile? — beats me, but I know it when I see it“.

To me at my current stage of thinking, the most important components of Agile development include:

  • short release cycles with working software to the customer as often as practical
  • safety, trust and openness in the development team
  • frequent (almost constant) and informal interaction between members of the team
  • open communication between the user and the developers
  • transparency and visibility of information
  • focus on solving the business issues
  • adaptability
  • emphasis on the practical over the ideal, but always pushing for incrementally better
  • an attitude that fosters creative solutions, dedication to solving real problems, and ownership of the problems, process and solutions

I think that the Agile manifesto wraps a lot of this up. It embraces the following values:

  • Individuals and interactions over processes and tools
  • Working software over comprehensive documentation
  • Customer collaboration over contract negotiation
  • Reponding to change over following a plan

Agile processes focus on adapting to real needs, rather than trying to predict them and then sticking to the predictions regardless of how accurate they turn out to be. They focus on meeting the needs of people over the needs of the development process itself.

There is a lot in the various methodologies that is good, but to me the philosophy for development espoused by these ideas is what its about. Methodologies need to adapt to the situation, just as other components of planning and process must.

Most of the information I have come across in the “formal” Agile methodologies completely overlook or dismiss distributed teams. This is just not well connected to the real world. Instead of dismissing those of us who live in distributed teams (and the numbers are growing), we need ideas about how to reach the goals of Agile development in the reality we live in. That mostly means finding ways to work closely together, to have transparency, code review, collaborative approaches to working and coding, and high levels of interaction and trust in teams that might be physically together only rarely.

For me, the biggest component to success over the long term in development projects is in the relationships–in trust and open communication–between the members of the development team, between the developers and users and customers, and between the development team and management. If those are missing, things can quickly fall apart.  Building and maintaining these in distributed teams, and when the team is not local to the customer, is challenging.  The real world many of us live and work in day to day, the team, the boss, and the customer might be literally an ocean away.  In this world the values of Agile development that I outlined above hold just as true.  Its just the charts scribbled on paper, pair programming on one computer, and in person stand up meetings that do not.

Categories: development Tags:

Drupal Text_Wiki Filter

March 7, 2008 Leave a comment

On the old version of my site I had a page about a module I wrote for Drupal 4.7 that added a filter using the PEAR Text_Wiki package. At the time I wrote it, there were no other good options for wiki markup in Drupal filters. I used the module on several sites, but I didn’t release it on drupal.org because I didn’t intend to maintain or support it over the longer term.

Since then, other people have created modules to provide wiki markup and other wiki-like functionality to Drupal. There’s a PEAR Wiki Filter module, which does basically what my module did except is maintained and has versions for Drupal 5 and 6. There’s also the new Flexifilter, which looks very promising but doesn’t have a “stable” release yet. And of course the Wikitools module goes a long way toward integrating wiki-like functionality into Drupal well beyond just markup.

I’m not sure if I was picking a product specifically for wiki that I would choose Drupal. Drupal is an excellent CMS and community collaboration tool. However, wikis are really their own thing, and there is quite a bit that wiki software does normally that has to be pieced together back into Drupal, making it work differently than it really is designed to work. I think that Drupal is the leader in what it is good at. That doesn’t make it the solution for everything.

On the other hand, if you need to use Drupal for some other reason, or if you have a Drupal site that needs some wiki functionality, take a look at the modules I mentioned. I think they will do the job better than resurrecting my old module.

Categories: drupal

Zend Framework

March 1, 2008 Leave a comment

Well, I’m continuing to look at Zend Framework. It has a lot of nice features, and a not insignificant learning curve to get what I would need out of it. Add to this that I don’t have time in my current work schedule to play with it, so I’m doing it in my “free” time. I’d like it to be quicker to figure out. Not that any particular piece of it is hard, there’s just lots of it and each part has to be unraveled and then plugged into what I’ve learned of the whole. I am currently working with 1.5, which is actually a Release Candidate at the moment, but earlier versions don’t include everything I need. Since I’m not going to be ready to use this in anything like a production app for a little while at least (assuming I end up with this approach), hopefully it will be a stable release by then.

Since I’m exploring ZF, I want to get as much out of it using ZF as I can, rather than combining it with other approaches. It might turn out that using a combination of resources is the best approach (as Wil Sinclair suggested in response to my last post on this), but I don’t want to use that as a crutch not to figure out what I can get out of ZF.

Some of the things I want to be able to do include:

  • Modular controller layout – I want to separate the controller code for various types of things. ZF allows for this pretty well. It took me a little fiddling to figure this part out, but most of that was me trying to get it to do variations. There are some pretty good articles about how to do this in addition to the documentation.
  • Modular model layout – I need to support different data sources, often of very different types. For example, the same application might need to interact with Postgres, MySQL, and a SOAP service. For Drupal I wrote a dataconnector module, and then a library for each different data source that belongs to this module. Much of what I had to do to get Drupal to do this sort of thing already exists in ZF. This is going to take more investigation to do in a way that is maintainable and easy to manage, but I haven’t had a chance to spend much time on it. Its possible that the directory layout of putting the model files in a shared directory is ok. Just don’t know yet.
  • Form and input validation – I’m probably going to write a post about this issue by itself soon. Its what I’m looking at now, and I’m not sure I’ve figured out the way that I think this would work best in the ZF context. Zend_Form has the server side validation nicely packaged. Actually, I’d like to do three levels of validation/filtering: at the client (for usability), at the controller for business logic and the first level of security filtering (this is what Zend_Form does), and at the model (for data integrity and injection avoidance). I need to investigate how I want to do model level filtering. That’s actually the easiest, I just haven’t looked at it yet in the ZF context. The database interaction layer isn’t sufficient for filtering by itself because at that level we don’t know all the uses we might be making of the fields. Just doing it at the controller layer isn’t sufficient because we don’t know that all data interactions will pass through any given controller, and we don’t want to miss anything. The next piece I’m going to investigate, though, is tying something like the jQuery validation plugin into Zend_Form.
  • I still haven’t gotten to XML_RPC and SOAP. There actually isn’t a stand-alone SOAP component yet, but the StrikeIron service component has a fairly basic SOAP base class.
  • Some core issues like logging and error (exception) handling. These are fairly boring, so I’ll put them off as long as I can.
  • Zend_Translate and Zend_Locale. I haven’t looked at these at all, but I need to. Like the previous bullet, this isn’t my favorite piece. I’m putting it here in part to remind myself not to skip it.
  • PDF creation. At FH (my day job) we have some stuff using PDFlib’s PPS libraries. I haven’t even thought about this yet.
  • I haven’t tackled AJAX for forms yet, although I don’t expect this to be a big issue from what I’ve seen of Zend_Form so far. In forms that are an integrated part of business process, I like forms that save each field in the background as it is filled out. I’ve used Dojo to do this in the past, but I think I’ll move it all to jQuery (largely because of Drupal’s influence). Not that there’s anything wrong with Dojo. Its a great tool kit. Its great to have such good choices.

There’s lots more to put on this list, but that will do for now. Tune in next week, same bat time, same bat channel. Or some time, some where, maybe.

Categories: PHP Tags: ,