Logaholic.de

Avatar

web development

Agavi chapter in the book “Quality Assurance in PHP Projects”

Later this year, there will be a book on “Quality Assurance in PHP Projects” by Sebastian Bergmann (the author of PHPUnit) and Stefan Priebsch. Their own teaser:

“Stefan Priebsch and myself, Sebastian Bergmann, are writing a book on “Quality Assurance in PHP Projects”. The book will be published in English and German at the same time later this year.
The idea for the book is that Stefan Priebsch and I write the introductory as well as the concluding chapters while other authors contribute case studies for the middle part of the book.”

Source: Quality Assurance in PHP Projects – Introduction

As I just discovered, one case study in this book is about Agavi, contributed by David Zülke. There is also an abstract for this chapter: “Testing Agavi: Why Test Isolation Matters”.

I’m looking forward to this book: interesting topic(s), interesting case studies.

Agavi vs Zend Framework Part 1 – Forms

Agavi and Zend Framework are two major MVC PHP5 Frameworks today. I am actively using both in two different projects.

I will discuss some differences, starting with Part 1 now: Forms.

Forms are used in nearly any web application where you expect user-input. Following the “never trust your users” rule, proper validation is one major (security-) subtopic of forms.

1. Building simple Forms:

Zend Framework:

a) define your Zend_Form object, once, including validation

    /**
     * @return Zend_Form
     */
    protected function getDemoForm()
    {
        $form = new Zend_Form();

        $form->addElement('textarea', 'comment', array(
            'label' => 'comment:',
            'required' => true,
            'validators' => array(
                array('StringLength', array(160), array(1))
            )
        ));
        $form->addElement('submit', 'submit', array(
            'label' => 'submit',
        ));

        return $form;
    }

b) trigger validation in your action, use the result if validation succeeds

$demoForm = $this->getDemoForm();
$request = $this->getRequest();

if ($request->isPost())
{
    if ($demoForm>isValid($request->getPost()))
    {
        doSomeStuff();
        redirectToSuccessAction();
    }
}

c) pass the form object to your view

$this->view->demoForm = $demoForm;

Agavi:

a) write html code for your form in your view

You know how that works. (Or see the Agavi documentation link below)

b) add validation to your write-action

The Agavi documentation prefers defining validators in a .xml file, per action, app/modules/Posts/validate/Add.xml:  (module Post, Action Add)

<?xml version="1.0" encoding="UTF-8"?>
<ae:configurations
  xmlns="http://agavi.org/agavi/config/parts/validators/1.0"
  xmlns:ae="http://agavi.org/agavi/config/global/envelope/1.0"
  parent="%core.module_dir%/Posts/config/validators.xml"
>
  <ae:configuration>

    <validators>
      <validator class="string">
        <arguments>
          <argument>title</argument>
        </arguments>
        <errors>
          <error>The title field has an invalid value.</error>
          <error for="required">Please provide a title.</error>
          <error for="max_error">The title must be shorter than 255 characters.</error>
        </errors>
        <ae:parameters>
          <ae:parameter name="max">255</ae:parameter>
        </ae:parameters>
      </validator>
    </validators>
  </ae:configuration>
</ae:configurations>

c) formpopulationfilter magic

“All we need to do is re-display our form on the error page and the AgaviFormPopulationFilter will perform all of those duties. To re-display the form we could either include it in the ErrorViews template or we could set the input template in the view.”

2. The Zend Framework way

+ Encapsulation

+ Abstraction

+ DRY

3. The Agavi way

- I have to keep an eye to input names, as they are needed at more than one place. Beware of templating guys changing the input names, breaking stuff.

- validating an action, not a single form/form object

- breaks the DRY principle, code duplication occurs

4. Conclusion

I prefer Zend Framework over Agavi for forms. The main reason is the encapsulation in ZF with the Zend_Form object.

I can have more separated forms with separate validation on one page. I can reuse forms withouth having (that much) duplicate code anywhere. I don’t have to make changes to multiple locations if changing input names or validation, just one object holds every needed information/configuration. Zend_Form also does the html output for me, application-persistent interface guaranteed (styling is done via css or decorators per form/element).

Sources:

How we use Event Driven Development in an Agavi project

We used the observer pattern to write our own EventObserver, which enables us to use Event Driven Development in an Agavi project.

Since we are working module-based, there are two simple steps to add an Event listener for your module to the system.

1. Add %module_dir%/config/event_listeners.xml

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <listeners>
        <event>
            <name>modules.forum.post.new</name>
            <callback>Forum_DefaultListener</callback>
        </event>
    </listeners>
</config>

The <name> element holds the event name or “channel”, the <callback> element holds the name of the listener-class.

2. Add %module_dir%/listeners/Forum_DefaultListener.class.php

(Note: callback name goes here as you can see, for autoloading)

class Forum_DefaultListener implements EventListenerInterface
{
    public static function listenToEvent(Event $event) {
        $name = $event->getName();
        switch($name) {
            case 'modules.forum.post.new':
                throw new HelloWorldException();
        }
    }
}

Listening to ‘modules.forum.post.new’ events is working from this point ;)

Firing events is as easy as this, anywhere in your module-code:

EventObserver::getInstance()
    ->notify(new Event('modules.forum.post.new', $message));

This call will find its way to the configured listener, Forum_DefaultListener, and Forum_DefaultListener::listenToEvent (like any other listener) will be called with an Event, including the passed $message object.

,