Reputation: 1167
I got two models in Laravel: Label
class Label extends \Eloquent
{
protected $fillable = [
'channel_id',
'name',
'color',
];
public function channel()
{
return $this->belongsTo('App\Channel');
}
}
And Channel
class Channel extends \Eloquent
{
protected $fillable = [
'name',
];
public function labels()
{
return $this->hasMany('App\Label');
}
}
Now when a label is deleted, I want to make sure, the label belongs to the channel.
This works pretty good, as it even is atomic, so the row will just be deleted, if the label really belongs to the channel.
LabelController:
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
$channel = $this->getChannel();
Label::where('id', $id)
->where('channel_id', $channel->id)
->delete();
return back();
}
And my question is now: How to build that with Eloquent, so it is elegant? Something like:
$channel->labels()->destroy($id);
But there is no destroy function on the relation.
I managed to achieve something in the right direction:
$channel->labels()->find($id)->delete();
This deletes the label with $id BUT just if the label has the right channel_id assigned. If not, I get the following error, which I could catch and handle:
FatalThrowableError (E_ERROR) Call to a member function delete() on null
Still, as Apache is threaded, there could be the case that another thread changes the channel_id after I read it. So the only way besides my query is to run a transaction?
Upvotes: 9
Views: 15662
Reputation: 594
If you want to delete related items of your model but not model itself you can do like this:
$channel->labels()->delete();
It will delete all labels related to the channel.
If you want to delete just some of labels you can use where()
$channel->labels()->where('id',1)->delete();
Also if your relation is many to many it will delete from third table too.
Upvotes: 22
Reputation: 455
You can use findorfail:
$channel->labels()->findOrFail($id)->delete();
Upvotes: 0
Reputation: 941
You mentioned that, you first want to check if a label has a channel. If so, then it should be deleted.
You can try something like this though:
$label = Label::find($id);
if ($label->has('channel')) {
$label->delete();
}
Upvotes: 1