Laravel - 如果不存在关联则删除

8

以下是其中一个模型。如果没有其他模型引用它,我想仅删除电信条目。最好的方法是什么?

namespace App;

use Illuminate\Database\Eloquent\Model;

class Telco extends Model
{
    public function operators()
    {
        return $this->hasMany('App\Operator');
    }

    public function packages()
    {
        return $this->hasMany('App\Package');
    }

    public function topups()
    {
        return $this->hasMany('App\Topup');
    }

    public function users()
    {
        return $this->morphMany('App\User', 'owner');
    }

    public function subscribers()
    {
        return $this->hasManyThrough('App\Subscriber', 'App\Operator');
    }
}

在删除时,您必须检查引用外键的每个其他表记录的存在。 - Sagar Gautam
如果您的关系正确,请尝试删除它并缓存异常(如果模型有子项,则会触发异常)。 - aaron0207
@SagarGautam 那会是一个很长的方法,有没有更有效率的简短形式? - Mohammad
@Mohammad,你需要在每个相关模型中检查记录的存在。最好在Telco模型中定义一个布尔函数。当你想要删除时,调用这个函数,并在没有相关数据存在时删除数据。 - Sagar Gautam
也许你的答案在这里: https://stackoverflow.com/questions/34136141/laravel-only-delete-a-model-if-no-related-model-exist - nirajan Kayastha
3个回答

16

您可以使用deleting模型事件,并在删除之前检查是否有相关记录,如果存在任何记录,则可以防止删除。

在您的Telco模型中

protected static function boot()
{
    parent::boot();

    static::deleting(function($telco) {
        $relationMethods = ['operators', 'packages', 'topups', 'users'];

        foreach ($relationMethods as $relationMethod) {
            if ($telco->$relationMethod()->count() > 0) {
                return false;
            }
        }
    });
}

这个方法应该在哪里使用?控制器(Controller)还是模型(Model)? - Mohammad
在您的电信模型中 - chanafdo

4
$relationships = array('operators', 'packages', 'topups', 'users', 'subscribers');

$telco = Telco::find($id);
$should_delete = true;

foreach($relationships as $r) {
    if ($telco->$r->isNotEmpty()) {
        $should_delete = false;
        break;
    }
}

if ($should_delete == true) {
    $telco->delete();
}

我知道这样不太好看,但我认为它应该有效。如果您喜欢让这个看起来更好看一些,只需调用每个关系属性并检查是否返回一个空集合(表示没有关系)。

如果所有关系都为空,则删除!


1
在看了这里的答案之后,我不想将static function boot复制粘贴到每个需要它的模型中。因此,我创建了一个名为SecureDeletetrait。我将@chanafdo的foreach放入了SecureDelete中的一个public function中。
这样,我就可以将其重用于需要它的模型中。

SecureDelete.php

trait SecureDelete
{
    /**
     * Delete only when there is no reference to other models.
     *
     * @param array $relations
     * @return response
     */
    public function secureDelete(String ...$relations)
    {
        $hasRelation = false;
        foreach ($relations as $relation) {
            if ($this->$relation()->withTrashed()->count()) {
                $hasRelation = true;
                break;
            }
        }

        if ($hasRelation) {
            $this->delete();
        } else {
            $this->forceDelete();
        }
    }
}

在���要的模型中添加use SecureDelete
use Illuminate\Database\Eloquent\Model;
use App\Traits\SecureDelete;
class Telco extends Model
{
    use SecureDelete;

    public function operators()
    {
        return $this->hasMany('App\Operator');
    }

    // other eloquent relationships (packages, topups, etc)
}

TelcoController.php

public function destroy(Telco $telco)
{
    return $telco->secureDelete('operators', 'packages', 'topups');
}

此外,您还可以创建一个自定义模型,例如BaseModel.php,继承Illuminate\Database\Eloquent\Model而不是使用Trait,将function secureDelete放在那里,并将您的模型更改为extends BaseModel。请保留HTML标签。

1
如果 hasRelation 返回 true 表示它存在于记录中,那么为什么要防止删除模型?我不理解这一部分。 - FeRcHo
@FeRcHo 是的,默认情况下,如果您想删除与其他表相关联的数据,则程序将抛出数据库错误和HTTP状态500。我的代码只是检查关系是否存在并软删除它,如果没有关系存在则硬删除它。 - Christhofer Natalius
OP不想软硬删除记录,如果关系存在的话。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接