1
votes

I am working with Zend Framework 1.12.1

I am trying to use a "save" method on a row from Zend_Db_Table_Abstract. As I understand this method should automatically decide whether to save or update a row in a table. I created two forms, one is for creating a record in database, another is for updating. It works perfect with create a new record. Method uses INSERT MySQL command. When I am trying to update the row, instead of choosing MySQL command UPDATE, save() method still chooses INSERT and duplicates a record in the table.

Here's a full error log:

Message: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'France' for key 'country'

Stack trace:

#0 C:\wamp\zf\library\Zend\Db\Statement.php(303): Zend_Db_Statement_Pdo->_execute(Array)
#1 C:\wamp\zf\library\Zend\Db\Adapter\Abstract.php(480): Zend_Db_Statement->execute(Array)
#2 C:\wamp\zf\library\Zend\Db\Adapter\Pdo\Abstract.php(238): Zend_Db_Adapter_Abstract->query('INSERT INTO `co...', Array)
#3 C:\wamp\zf\library\Zend\Db\Adapter\Abstract.php(576): Zend_Db_Adapter_Pdo_Abstract->query('INSERT INTO `co...', Array)
#4 C:\wamp\zf\library\Zend\Db\Table\Abstract.php(1076): Zend_Db_Adapter_Abstract->insert('countries', Array)
#5 C:\wamp\zf\library\Zend\Db\Table\Row\Abstract.php(467): Zend_Db_Table_Abstract->insert(Array)
#6 C:\wamp\zf\library\Zend\Db\Table\Row\Abstract.php(438): Zend_Db_Table_Row_Abstract->_doInsert()
#7 C:\wamp\www\website\library\App\Data.php(34): Zend_Db_Table_Row_Abstract->save()
#8 C:\wamp\www\website\application\controllers\CountryController.php(82): App_Data->save()
#9 C:\wamp\zf\library\Zend\Controller\Action.php(516): CountryController->editAction()
#10 C:\wamp\zf\library\Zend\Controller\Dispatcher\Standard.php(308): Zend_Controller_Action->dispatch('editAction')
#11 C:\wamp\zf\library\Zend\Controller\Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#12 C:\wamp\zf\library\Zend\Application\Bootstrap\Bootstrap.php(97): Zend_Controller_Front->dispatch()
#13 C:\wamp\zf\library\Zend\Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
#14 C:\wamp\www\website\public\index.php(26): Zend_Application->run()
#15 {main}  

I am trying to update a record in the table {'id'=>'1', 'country'=>'France', 'continent'=>'Europe', 'created'=>'2013-03-07 10:10', 'modified'=>''}

Is there way to force method save() to choose Zend_Db_Table_Row_Abstract->_doUpdate() method instead of _doInsert()?

Thak you very much.

1
Show the data array you are saving ? If you set the id field it will update the record rather try to insert the new one. - Rikesh
The array called to the form is Array ([id] => 1, [country] => France, [continent] => Europe, [created] => 2013-03-06 19:27:09, [modified] => ). After changes are made, Zend_Db_Table_Row_Abstract looks like this: ( 'controller' => 'country', 'action' => 'edit', 'id' => '1', 'module' => 'default', 'country' => 'France', 'continent' => 'Europe', 'created' => '2013-03-06 19:27:09', 'modified' => '2013-03-07 00:00:00', 'submit' => 'Add Country', ) - Midnight Coder
Zend_Db_Table_Row will update only if your Zend_Db_Table_Row was previously fetched from the database, if you create a new Zend_Db_Table_Row, even if it matches an existing PK or UNIQUE key, it will save it through an INSERT and not an UPDATE - Matteo Tassinari
I am fetching a row from database in the construct method of the model with method $this->_row = $this->_dbTable->find($id)->current() where id is the country id. _row is protected variable inside Country model. - Midnight Coder

1 Answers

0
votes

You may need to update your question to add some code because at the moment we are all guessing.

Here is a simple example of how save() works in a mapper, using an entity model in place of an array.

public function saveArtist(Music_Model_Artist $artist)
    {
        //if id is set fetch the row
        if (!is_null($artist->id)) {
            $select = $this->getGateway()->select();
            $select->where('id = ?', $artist->id);
            $row = $this->getGateway()->fetchRow($select);
        } else {
            //if id is not set create a new row
            $row = $this->getGateway()->createRow();
        }
        // this data is added to the record always
        $row->name = $artist->name;
        //save/update the row
        $row->save();
        //return the whole row, my preference as save() just returns primary key of row.
        return $row;
    }

What really happens is if you submit an existing row save() will UPDATE if you create a new row save() will INSERT. There is no magic in this method you control what it does based on the data passed to it. Be specific and it works great.

Your app appears to be doing an INSERT when you intend for it to be doing an UPDATE.