Check if entity exists in database before inserting with Doctrine
Whenever I insert an entity that already exists in the database, I get an error because there is one single constraint on one of the fields ( email
).
So, I want to check if it exists; if not, I paste it.
My code looks like this:
$q = Doctrine_Query::create()
->from('User u')
->where('u.email = ?', $email);
$object = $q->fetchOne();
if( ! is_object($object)) {
$user = new User();
$user-email = $email;
$user->save();
}
Is there an easier way to do this?
a source to share
Place the code you have in your UserTable class like insertIfNotExists()
:
public function insertIfNotExists(User $user)
{
// Check if it exists first
$q = self::create("u")
->where("u.email = ?", $user->email)
->execute();
// Do we have any?
if ($q->count())
{
// Yes, return the existing one
return $q->getFirst();
}
// No, save and return the newly created one
$user->save();
return $user;
}
Now you can call the method, and the returned object will be the existing record (if any) or the one you just created.
a source to share
I had to face a similar issue when creating a database backed database. To prevent warning fatigue, I assign each log message a UID that is a hash of its identifying content and make the UID a unique key.
Naturally, this requires determining if an existing entry exists that matches this UID value (in my case, I increment the value count
for this log entry and touch its flag updated_at
).
I ended up redefining Doctrine_Record::save()
in my model class, similar to this (code adjusted to be more relevant to your situation):
/** Persists the changes made to this object and its relations into the
* database.
*
* @param $conn Doctrine_Connection
* @return void
*/
public function save( Doctrine_Connection $conn = null )
{
/* Invoke pre-save hooks. */
$this->invokeSaveHooks('pre', 'save');
/* Check to see if a duplicate object already exists. */
if( $existing = $this->getTable()->findDuplicate($this) )
{
/* Handle duplicate. In this case, we will return without saving. */
return;
}
parent::save($conn);
}
UserTable::findDuplicate()
as follows:
/** Locates an existing record that matches the specified user email (but
* without matching its PK value, if applicable).
*
* @param $user User
*
* @return User|bool
*/
public function findDuplicate( User $user )
{
$q =
$this->createQuery('u')
->andWhere('u.email = ?', $user->email)
->limit(1);
if( $user->exists() )
{
$q->andWhere('u.id != ?', $user->id);
}
return $q->fetchOne();
}
Note that this is probably the best approach for rewriting preSave()
, not save()
in your model. In my case, I had to wait for the pre-save quotes to complete (the UID was set using the Doctrine template I created ), so I had to overwrite instead save()
.