Zend_Form and dependency injection

3 messages Options
Embed this post
Permalink
Hector Virgen

Zend_Form and dependency injection

Reply Threaded More More options
Print post
Permalink
Hello,

I am building a search form that contains many fields and options that are generated dynamically based on the user. For example, one field is a large multiCheckbox that contains a list of "publishers" the user is allowed to search through.

My form extends Zend_Form and does all of its work in init(), meaning I need to know which user the form is being built for.

Initially, I had the form pull the current user from the session to build the options. This works fine on the web.

But now I need to unit-test this form (or, more specifically, a service that contains a factory method for this form). Since init() is run at the end of Zend_Form's constructor, I am not given an opportunity to inject a user stub until after the form has been created (which is too late).

I have a few options here on how to get around this:

A. Overload Zend_Form's constructor to add an optional $user param:

public function __construct($options = null, UserInteface $user = null)
{
    $this->_user = $user;
    parent::__construct($options);
}

B. Make my form a dumb container with empty multiCheckbox fields and inject the options via a service layer or wrapper class. It would be nice if there was a Zend_Form_Interface so that I don't have to update all of my code that uses this form.

C. Make my form work without a user by ignoring fields that require user permissions to populate.

Any suggestions on these approaches? Is there another way to safely inject a user stub into Zend_Form or is my form handling too much responsibility by checking user permissions? Thanks for the help!

--
Hector
weierophinney

Re: Zend_Form and dependency injection

Reply Threaded More More options
Print post
Permalink
-- Hector Virgen <[hidden email]> wrote
(on Friday, 06 November 2009, 09:05 AM -0800):

> I am building a search form that contains many fields and options that are
> generated dynamically based on the user. For example, one field is a large
> multiCheckbox that contains a list of "publishers" the user is allowed to
> search through.
>
> My form extends Zend_Form and does all of its work in init(), meaning I need to
> know which user the form is being built for.
>
> Initially, I had the form pull the current user from the session to build the
> options. This works fine on the web.
>
> But now I need to unit-test this form (or, more specifically, a service that
> contains a factory method for this form). Since init() is run at the end of
> Zend_Form's constructor, I am not given an opportunity to inject a user stub
> until after the form has been created (which is too late).

Easy way to take care of this: create a setter method for injecting the
user:

    class My_Form extends Zend_Form
    {
        protected $_user;

        public function setUser(UserInterface $user)
        {
            $this->_user = $user;
            return $this;
        }

        public function getUser()
        {
            return $this->_user;
        }
    }

setOptions(), which is called during __construct(), will check to see if
a given option key matches an existing setter; if so, it passes the
value to that setter. Thus:

    $form = new My_Form(array(
        'user' => $user,
    ));

will now work.

You can then do some checks later to see if you have a user object or
not, or even have getUser() raise an exception if none has been set --
allowing you to test.

> I have a few options here on how to get around this:
>
> A. Overload Zend_Form's constructor to add an optional $user param:
>
> public function __construct($options = null, UserInteface $user = null)
> {
>     $this->_user = $user;
>     parent::__construct($options);
> }
>
> B. Make my form a dumb container with empty multiCheckbox fields and inject the
> options via a service layer or wrapper class. It would be nice if there was a
> Zend_Form_Interface so that I don't have to update all of my code that uses
> this form.
>
> C. Make my form work without a user by ignoring fields that require user
> permissions to populate.
>
> Any suggestions on these approaches? Is there another way to safely inject a
> user stub into Zend_Form or is my form handling too much responsibility by
> checking user permissions? Thanks for the help!


--
Matthew Weier O'Phinney
Project Lead            | [hidden email]
Zend Framework          | http://framework.zend.com/
Hector Virgen

Re: Zend_Form and dependency injection

Reply Threaded More More options
Print post
Permalink
Wow, I had no idea you could do that! Very nice :) I'll update my form now. Thanks!

--
Hector


On Fri, Nov 6, 2009 at 11:17 AM, Matthew Weier O'Phinney <[hidden email]> wrote:
-- Hector Virgen <[hidden email]> wrote
(on Friday, 06 November 2009, 09:05 AM -0800):
> I am building a search form that contains many fields and options that are
> generated dynamically based on the user. For example, one field is a large
> multiCheckbox that contains a list of "publishers" the user is allowed to
> search through.
>
> My form extends Zend_Form and does all of its work in init(), meaning I need to
> know which user the form is being built for.
>
> Initially, I had the form pull the current user from the session to build the
> options. This works fine on the web.
>
> But now I need to unit-test this form (or, more specifically, a service that
> contains a factory method for this form). Since init() is run at the end of
> Zend_Form's constructor, I am not given an opportunity to inject a user stub
> until after the form has been created (which is too late).

Easy way to take care of this: create a setter method for injecting the
user:

   class My_Form extends Zend_Form
   {
       protected $_user;

       public function setUser(UserInterface $user)
       {
           $this->_user = $user;
           return $this;
       }

       public function getUser()
       {
           return $this->_user;
       }
   }

setOptions(), which is called during __construct(), will check to see if
a given option key matches an existing setter; if so, it passes the
value to that setter. Thus:

   $form = new My_Form(array(
       'user' => $user,
   ));

will now work.

You can then do some checks later to see if you have a user object or
not, or even have getUser() raise an exception if none has been set --
allowing you to test.

> I have a few options here on how to get around this:
>
> A. Overload Zend_Form's constructor to add an optional $user param:
>
> public function __construct($options = null, UserInteface $user = null)
> {
>     $this->_user = $user;
>     parent::__construct($options);
> }
>
> B. Make my form a dumb container with empty multiCheckbox fields and inject the
> options via a service layer or wrapper class. It would be nice if there was a
> Zend_Form_Interface so that I don't have to update all of my code that uses
> this form.
>
> C. Make my form work without a user by ignoring fields that require user
> permissions to populate.
>
> Any suggestions on these approaches? Is there another way to safely inject a
> user stub into Zend_Form or is my form handling too much responsibility by
> checking user permissions? Thanks for the help!


--
Matthew Weier O'Phinney
Project Lead            | [hidden email]
Zend Framework          | http://framework.zend.com/