views:

110

answers:

2

I am having problems getting validation to work for a form built using Zend_Form.

The idea is this: I have two dropdown. One is a list of players. The other is a list of free agents who play the same position as the player. I am using an onChange javascript callback to run some Ajax code that replaces the free agent list dropdown with a new one at the position of the player they've selected from the player dropdown.

Now, perhaps this is the wrong way, but I built the form by creating an instance of Zend_Form and then creating all these setX methods that add elements to the form. My reasoning was that I wanted to display certain elements in specific places on the page, not just output $this->form on my template.

The problem appears to be when I get the form post back, the validator seems to not know about the validation rule I set up for the free agent drop down. Here's some relevant code to look at. I'm a relative ZF n00b so feel free to tell me I am not doing things the ZF way if it leaps out at you.

The action in the controller:

public function indexAction()
{
    if ($this->getRequest()->isPost()) {
        $form = new Baseball_Form_Transactions();

        if ($form->isValid($this->_request->getPost())) {
            $data = $this->_request->getPost();
            $leagueInfo = Doctrine::getTable('League')->findOneByShortName($data['shortLeagueName'])->toArray();

            // Create the request top drop an existing player       
            $transactionInfo = array(
                'league_id' => $leagueInfo['id'],
                'team_id' => $data['teamId'],
                'player_id' => $data['players'],
                'type' => 'drop',
                'target_team_id' => 0,
                'transaction_date' => date('Y-m-d H:m:s')
            );
            $transaction = new Transaction();
            $transaction->fromArray($transactionInfo);
            $transaction->save();

            // Now we do the request to add a player
            $transactionInfo['team_id'] = 0;
            $transactionInfo['player_id'] = $data['freeAgents'];
            $transactionInfo['target_team_id'] = $data['teamId'];
            $transactionInfo['type'] = 'add';
            $transaction = new Transaction();
            $transaction->fromArray($transactionInfo);
            $transaction->save();
            $this->_flashMessenger->addMessage('Added transaction');
        }
    }

    $options = array(
        'teamId' => $this->teamId,
        'position' => 'C',
        'leagueShortName' => $this->league
    );

    $this->transactionForm->setMyPlayers($options);
    $this->transactionForm->setFreeAgents($options);
    $this->transactionForm->setTeamId($options);
    $this->transactionForm->setShortLeagueName($options);
    $this->view->transactionForm = $this->transactionForm;
    $this->view->messages = $this->_flashMessenger->getMessages();
    $transaction = new Transaction();
    $this->view->transactions = $transaction->byTeam($options);
}

Next we have the form itself

public function setMyPlayers($options)
{
    $data = Doctrine::getTable('Team')->find($options['teamId']);
    $players = array();

    foreach ($data->Players->toArray() as $player) {
        $players[$player['id']] = "{$player['position']} - {$player['first_name']} {$player['last_name']}";
    }

    $playersSelect = new Zend_Form_Element_Select(
        'players', 
        array(
            'required' => true,
            'label' => 'Players',
            'multiOptions' => $players,
        )
    );

    $this->addElement($playersSelect);
}

public function setFreeAgents($options)
{
    $q = Doctrine_Query::create()
        ->select('CONCAT(p.first_name, " ", p.last_name) as full_name, p.id, p.position')
        ->from('Player p')
        ->leftJoin('p.Teams t')
        ->leftJoin('t.League l ON l.short_name = ?', $options['leagueShortName'])
        ->where('t.id IS NULL')
        ->andWhere('p.position = ?', $options['position'])
        ->orderBy('p.last_name');
    $q->setHydrationMode(Doctrine_Core::HYDRATE_ARRAY);
    $data = $q->execute();
    $freeAgents = array();

    foreach ($data as $player) {
        $freeAgents[$player['id']] = $player['full_name'];
    }

    $freeAgentsSelect = new Zend_Form_Element_Select(
        'freeAgents',
        array(
            'label' => 'Free Agents',
            'multiOptions' => $freeAgents,
            'size' => 15
        )
    );
    $freeAgentsSelect->setRequired(true);
    $this->addElement($freeAgentsSelect);
}

public function setShortLeagueName($options)
{
    $shortLeagueNameHidden = new Zend_Form_Element_Hidden(
        'shortLeagueName',
        array('value' => $options['leagueShortName'])
    );
    $this->addElement($shortLeagueNameHidden);
}

public function setTeamId($options)
{
    $teamIdHidden = new Zend_Form_Element_Hidden(
        'teamId',
        array('value' => $options['teamId'])
    );
    $this->addElement($teamIdHidden);
}

There is no init or __construct() method in the form.

My problem seems simple enough: reject the form contents as invalid if they have not selected someone from the free agent list. Right now, it sails through as valid. I've spent some considerable time searching online for an answer, and haven't been able to find it.

Thanks in advance for any help.

+1  A: 

You need to set up the form's fields every request. try this:

public function indexAction()
{
    $form = new Baseball_Form_Transactions();
    $options = array(
        'teamId' => $this->teamId,
        'position' => 'C',
        'leagueShortName' => $this->league
    );

    $form->setMyPlayers($options);
    $form->setFreeAgents($options);
    $form->setTeamId($options);
    $form->setShortLeagueName($options);
    $this->transactionForm = $form;

    if ($this->getRequest()->isPost()) {

        if ($form->isValid($this->_request->getPost())) {
            $data = $form->getValues();
            $leagueInfo = Doctrine::getTable('League')->findOneByShortName($data['shortLeagueName'])->toArray();

            // Create the request top drop an existing player       
            $transactionInfo = array(
                'league_id' => $leagueInfo['id'],
                'team_id' => $data['teamId'],
                'player_id' => $data['players'],
                'type' => 'drop',
                'target_team_id' => 0,
                'transaction_date' => date('Y-m-d H:m:s')
            );
            $transaction = new Transaction();
            $transaction->fromArray($transactionInfo);
            $transaction->save();

            // Now we do the request to add a player
            $transactionInfo['team_id'] = 0;
            $transactionInfo['player_id'] = $data['freeAgents'];
            $transactionInfo['target_team_id'] = $data['teamId'];
            $transactionInfo['type'] = 'add';
            $transaction = new Transaction();
            $transaction->fromArray($transactionInfo);
            $transaction->save();
            $this->_flashMessenger->addMessage('Added transaction');
        }
    }

    $this->view->transactionForm = $form;
    $this->view->messages = $this->_flashMessenger->getMessages();
    $transaction = new Transaction();
    $this->view->transactions = $transaction->byTeam($options);
}
Rob Allen
Thanks Rob...I *knew* I was doing something subtly wrong
GrumpyCanuck
+1  A: 

Not specific to your question, but just FYI, $data should pull from $form->getValues() so that the data is properly filtered.

Matthew Turland
Yeah - I did that in the code sample I provided, but forgot to call it out.
Rob Allen