avatarHafiq Iqmal

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

2208

Abstract

ss="hljs-built_in">self</span>::<span class="hljs-variable constant_">DELIMITER</span>, <span class="hljs-variable">model</span>-&gt;{<span class="hljs-variable">column</span>})[<span class="hljs-number">1</span>] ?? <span class="hljs-literal">null</span>)) {
<span class="hljs-variable">model</span>-&gt;{<span class="hljs-variable">column</span>} = <span class="hljs-variable">$value</span>; }
}
}

<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleted</span>(<span class="hljs-params">Model <span class="hljs-variable">$model</span></span>) 
</span>{        
    <span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$model</span>-&gt;<span class="hljs-title function_ invoke__">getDuplicateAvoidColumns</span>() <span class="hljs-keyword">as</span> <span class="hljs-variable">$column</span>) { 
       <span class="hljs-variable">$newValue</span> = <span class="hljs-title function_ invoke__">time</span>().<span class="hljs-built_in">self</span>::<span class="hljs-variable constant_">DELIMITER</span>.<span class="hljs-variable">$model</span>-&gt;{<span class="hljs-variable">$column</span>};              
       <span class="hljs-variable">$model</span>-&gt;{<span class="hljs-variable">$column</span>} = <span class="hljs-variable">$newValue</span>;       
    }         
    <span class="hljs-variable">$model</span>-&gt;<span class="hljs-title function_ invoke__">save</span>();    

} }</pre></div><p id="4b0e">After deleted, the selected fields will be prepend by timestamp and separated by delimiter.</p><p id="985b"><code>[email protected]</code> => <code>[email protected]</code></p><p id="b584">If the data want to be restore, restoring event will trigger and remove the delimiter</p><h2 id="5682">2. Create a trait and use it in any of your model that use</h2><div id="b773"><pre><span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">AvoidDuplicateConstraintSoftDelete</span> </span>{
<span class="hljs-keyword">pub

Options

lic</span> <span class="hljs-built_in">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bootAvoidDuplicateConstraintSoftDelete</span>(<span class="hljs-params"></span>)
</span>{
<span class="hljs-built_in">static</span>::<span class="hljs-title function_ invoke__">observe</span>(<span class="hljs-title function_ invoke__">app</span>(<span class="hljs-title class_">UniqueSoftDeleteObserver</span>::<span class="hljs-variable language_">class</span>));
} </pre></div><div id="6a6d"><pre> <span class="hljs-keyword"> public</span> function getDuplicateAvoidColumns()<span class="hljs-keyword"> :</span><span class="hljs-built_in"> array </span> {
<span class="hljs-built_in"> return </span>[];
} }</pre></div><h2 id="45fa">3. Lets implement it,</h2><div id="9f02"><pre>class <span class="hljs-keyword">User</span> <span class="hljs-title">{ use</span> SoftDeletes, AvoidDuplicateConstraintSoftDelete;</pre></div><div id="e5a4"><pre> ... ...</pre></div><div id="1448"><pre> <span class="hljs-keyword"> public</span> function getDuplicateAvoidColumns()<span class="hljs-keyword"> :</span><span class="hljs-built_in"> array </span> {
<span class="hljs-built_in"> return </span>[ 'email' ];
}</pre></div><div id="5314"><pre>}</pre></div><h2 id="8869">4. Done!</h2><p id="5c6a">Incase, your database table don’t use unique constraint, you can validate like below,</p><div id="387d"><pre><span class="hljs-keyword">return</span> [ <span class="hljs-string">'email'</span> => [ <span class="hljs-string">'required'</span>, Rule::unique<span class="hljs-function"><span class="hljs-params">(<span class="hljs-string">'users'</span>, <span class="hljs-string">'email'</span>)</span>-></span>ignore<span class="hljs-function"><span class="hljs-params">($email)</span>-></span>withTrashed(), <span class="hljs-regexp">//'unique:user,email,NULL,NULL,deleted_at,NULL' ] ]</span></pre></div><p id="1999">That’s it 😄</p><p id="e8e7">Thanks for your time….</p></article></body>

wallpaperscraft.com

Laravel SoftDelete Avoid Unique Constraint Problem

When models are soft deleted, they are not actually removed from your database. Laravel use deleted_at field to indicate the visibility of the data when retrieved. If a model has a non-null deleted_at value, the model has been soft deleted and not showing.

But, since its not deleted from database, the unique constraint issue came out. Let’s say, User table must have unique email field and you want to soft delete 1 data. Then, you want to insert the same email address and error occurred because of its already exist.

So, there is a solution for it.

1. Create an observer

class UniqueSoftDeleteObserver
{    
    private const DELIMITER = '--';   
  
    public function restoring(Model $model) 
    {        
        if (!$model->trashed()) {
            return;
        }
        foreach ($model->getDuplicateAvoidColumns() as $column) {
           if ($value = (explode(self::DELIMITER, $model->{$column})[1] ?? null)) {                    
               $model->{$column} = $value;
           }        
        }    
    }
     
    public function deleted(Model $model) 
    {        
        foreach ($model->getDuplicateAvoidColumns() as $column) { 
           $newValue = time().self::DELIMITER.$model->{$column};              
           $model->{$column} = $newValue;       
        }         
        $model->save();    
   }
}

After deleted, the selected fields will be prepend by timestamp and separated by delimiter.

[email protected] => [email protected]

If the data want to be restore, restoring event will trigger and remove the delimiter

2. Create a trait and use it in any of your model that use

trait AvoidDuplicateConstraintSoftDelete
{    
     public static function bootAvoidDuplicateConstraintSoftDelete()         
     {          
         static::observe(app(UniqueSoftDeleteObserver::class));    
     }     
     public function getDuplicateAvoidColumns() : array 
     {        
         return [];    
     }
}

3. Lets implement it,

class User
{
     use SoftDeletes, AvoidDuplicateConstraintSoftDelete;
     ...
     ...
     public function getDuplicateAvoidColumns() : array 
     {        
         return [
              'email'
         ];    
     }
}

4. Done!

Incase, your database table don’t use unique constraint, you can validate like below,

return [
    'email' => [
      'required',
      Rule::unique('users', 'email')->ignore($email)->withTrashed(),
      //'unique:user,email,NULL,NULL,deleted_at,NULL' 
    ]
]

That’s it 😄

Thanks for your time….

Laravel
Eloquent
PHP
Database
Constraints
Recommended from ReadMedium