Duplicate entry - _getUpdateCondition not working

chrisj

Active member
I set up a cron go through the users and create a psn record for each user. It creates the record correctly but when I run the command again, instead of trying to update the record, gets a duplicate entry error. I was following Fuhrmann's read and write to database and cron tutorials.

Error
Code:
Mysqli statement execute error : Duplicate entry '1' for key 'PRIMARY'
 
Zend_Db_Statement_Mysqli->_execute() in Zend/Db/Statement.php at line 317
Zend_Db_Statement->execute() in Zend/Db/Adapter/Abstract.php at line 479
Zend_Db_Adapter_Abstract->query() in Zend/Db/Adapter/Abstract.php at line 574
Zend_Db_Adapter_Abstract->insert() in XenForo/DataWriter.php at line 1591
XenForo_DataWriter->_insert() in XenForo/DataWriter.php at line 1580
XenForo_DataWriter->_save() in XenForo/DataWriter.php at line 1381
XenForo_DataWriter->save() in PsnLeaderboards/CronEntry.php at line 109
PsnLeaderboards_CronEntry::getPsnUsers()
call_user_func() in XenForo/Model/Cron.php at line 356
XenForo_Model_Cron->runEntry() in XenForo/ControllerAdmin/Cron.php at line 204
XenForo_ControllerAdmin_Cron->actionRun() in XenForo/FrontController.php at line 310
XenForo_FrontController->dispatch() in XenForo/FrontController.php at line 132
XenForo_FrontController->run() in /Users/chris/Development/xf_dev/admin.php at line 13

DataWriter
PHP:
<?php
class PsnLeaderboards_DataWriter_PsnUser extends XenForo_DataWriter
{
 /**
* Gets the fields that are defined for the table. See parent for explanation.
*
* @return array
*/
protected function _getFields() {
   return array(
       'psn_user' => array(
           'xf_user_id'=> array(
               'type'=> self::TYPE_UINT,
'required'=> true
           ),
           'username'=> array(
               'type'=> self::TYPE_STRING,
'required'=> true
           ),
           'country'=> array(
               'type'=> self::TYPE_STRING,
               'required'=> true
           ),
'avatar'=> array(
               'type'=> self::TYPE_STRING,
               'required'=> true
           ),
'color'=> array(
               'type'=> self::TYPE_STRING,
               'required'=> true
           ),
'psnplus'=> array(
               'type'=> self::TYPE_STRING,
               'required'=> true
           ),
'points'=> array(
               'type'=> self::TYPE_UINT,
               'required'=> true
           ),
'platinum'=> array(
               'type'=> self::TYPE_UINT,
               'required'=> true
           ),
'gold'=> array(
               'type'=> self::TYPE_UINT,
               'required'=> true
           ),
'silver'=> array(
               'type'=> self::TYPE_UINT,
               'required'=> true
           ),
'bronze'=> array(
               'type'=> self::TYPE_UINT,
               'required'=> true
           ),
       )
   );
}
 
/**
* Gets the actual existing data out of data that was passed in. See parent for explanation.
*
* @param mixed
*
* @see XenForo_DataWriter::_getExistingData()
*
* @return array|false
*/
protected function _getExistingData($data)
{
   if (!$id = $this->_getExistingPrimaryKey($data, 'xf_user_id'))
   {
       return false;
   }
 
   return array('psn_user' => $this->_getPsnUserModel()->getPsnUserById($id));
}
 
/**
* Gets SQL condition to update the existing record.
* 
* @see XenForo_DataWriter::_getUpdateCondition() 
*
* @return string
*/
protected function _getUpdateCondition($tableName)
{
   return 'xf_user_id = ' . $this->_db->quote($this->getExisting('xf_user_id'));
}
 
/**
* Get the psn user model.
*
* @return PsnLeaderboards_Model_PsnUser
*/
protected function _getPsnUserModel()
{
   return $this->getModelFromCache ( 'PsnLeaderboards_Model_PsnUser' );
}
}
?>
Model
PHP:
<?php
class PsnLeaderboards_Model_PsnUser extends Xenforo_Model
{
/**
* Get only one row using the data passed. 
*/
public function getPsnUserById($id)
{
   return $this->_getDb()->fetchRow('
       SELECT * FROM psn_user WHERE xf_user_id = ?', $id);
}
 
/**
* Get all the rows of our table.
*
*/
public function getAllPsnUser()
{
   return $this->fetchAllKeyed('SELECT * FROM psn_user ORDER BY points DESC', 'xf_user_id');
}
}
?>
 
If you want to update an existing record using your datawriter then you need to use setExistingData(). Here is a function from the model in one of my addons that writes out a node record:

Code:
	public function saveOptions(array $node)
	{
		if (!$node['node_id'])
		{
			return;
		}

		$dw = XenForo_DataWriter::create('NodesAsTabs_DataWriter_Options');

		$existing = $this->getOptionsById($node['node_id']);
		if (!empty($existing['node_id']))
		{
			$dw->setExistingData($existing['node_id']);
		}

		$dw->bulkSet($node);

		$dw->save();
	}

It starts by trying to select an existing record by node_id. If it exists then it calls setExistingData() before saving.
 
Top Bottom