doctrine save method update/insert based on unique field
I rea开发者_JAVA技巧d so many post and I found many variations about how to get save to insert vs update but couldn't find something that would work for me.
I am guessing that preSave would be the way to go if preSave() is being executed automaticly by save() if present.
columns:
email:
type: string(255)
unique: true
email: true
I need save() to check if a filed is set to be unique if so, to check if field data in this case email address is unique. Based on that info decide to insert or update posted fields that have changed.
Just adding a little more logic, there could be better ways of doing it, but this works for me.
public function preInsert($event) {
if ($this->state() == Doctrine_Record::STATE_TDIRTY) {
$r == findRecordInDatabaseUsingThis();
$this->assignIdentifier($r->id);
$this->refresh();
$this->state(Doctrine_Record::STATE_CLEAN); // STATE_DIRTY to do an update, this will just use the existing record without updating
$event->skipOperation();
}
}
}
public function preSave($event)
{
if (!$this->isUniqueEmail()) {
$event->skipOperation();
}
}
But I suggest you to use validators for this.
I guess Vladimir's answer right, you just need to add the update logic before skipOperation.
public function preSave($event)
{
if (!$this->isUniqueEmail()) {
// update logic
$event->skipOperation();
}
}
Sorry, but I can't comment on Vladimir's answer.
replace()
might work, if you include the row id.
I've just dug up this question after running into a similar situation. @Peter's answer is almost what I was looking for, but I've added a couple of changes.
/**
* Check if identical record exists before (re)inserting
* @param \Doctrine_Event $event
* @return void
*/
public function preInsert(\Doctrine_Event $event)
{
$existing = $this->getTable()->findOneBy('email', $this->email);
if ($existing) {
$this->assignIdentifier($existing->id);
$this->hydrate($existing->toArray());
$this->state(self::STATE_CLEAN);
$event->skipOperation();
}
}
Using hydrate()
instead of refresh()
means you perform 1 less SELECT query.
I know you're likely to have an answer to this problem (at least I hope you have), but I thought I'd add my solution for others with the same question.
I've also removed if ($this->state() === self::STATE_TDIRTY)
as preInsert()
only applies for TDIRTY records
I know I'm a bit late here, but I found this post on Google while I was trying to update a field in a preInsert hook. I couldn't do that following what you've done, since your goal is only to refresh the Doctrine-Record, not to update it in DB (from what I understand ^^)
To perform an update in DB, I had to use the lollowing code ( I was surprised that I had to call "save" again)
public function preInsert(Doctrine_Event $event)
{
/* @var $weighSameDate Doctrine_Collection */
$weighSameDate = Doctrine::getTable('BiometryWeightData')
->createQuery()
->where('user_id=?', $this->getUserId())
->where('date=?', $this->getDate())
->execute();
if (count($weighSameDate)) {
/* @var $weight BiometryWeightData */
$weight = $weighSameDate->getFirst();
if ($weight->getWeight() != $this->getWeight()) {
$previous = clone $this;
$this->assignIdentifier($weight->getId());
$this->hydrate($weight->toArray());
$this->setWeight($previous->getWeight());
$this->state(Doctrine_Record::STATE_DIRTY); // STATE_DIRTY to do an update
$this->save();
}
$event->skipOperation();
return;
}
parent::preInsert($event);
}
精彩评论