php - (Mysql) how do i update parent and its reference in backend?
Solution:
This is the way I would do it:
public function patch(Request $request)
{
Child::whereNotIn('id', array_column($request->childs, 'id'))->delete();
Child::upsert([
$request->childs
], ['id'], ['name']);
}
Answer
Solution:
If you don't want to soft delete the child you can apply forceDelete()
as below:
child::where('parent_id',Request->id)->forceDelete();
foreach($Request->childs as $item) {
if($item->id == null){
child::create['name'=>$item->name,'parent_id'=>$Request->id];
}
child::find($item->id)->update['name'=>$item->name];
}
Answer
Solution:
Oh, it's big problem. I solved it for my project, but not very happy with this solution.
What you get
$parent->childs()->sync($request['childs'])
if you pass true as second value - null childs will be removed
How you can get it
Add this code to AppServiceProvider::boot() - it's not my code, just copy pasted from somewhere and slightly improved
HasMany::macro('sync', function (array $data, $deleting = true) {
/** @var HasMany $this */
$changes = [
'created' => [], 'deleted' => [], 'updated' => [],
];
$relatedKeyName = $this->getRelated()->getKeyName();
$current = $this->newQuery()->pluck($relatedKeyName)->all();
$castKey = function ($value) {
if (is_null($value)) {
return $value;
}
return is_numeric($value) ? (int) $value : (string) $value;
};
$castKeys = function ($keys) use ($castKey) {
return (array) array_map(function ($key) use ($castKey) {
return $castKey($key);
}, $keys);
};
$deletedKeys = array_diff($current, $castKeys(
Arr::pluck($data, $relatedKeyName))
);
if ($deleting && count($deletedKeys) > 0) {
$this->getRelated()->destroy($deletedKeys);
$changes['deleted'] = $deletedKeys;
}
$newRows = Arr::where($data, function ($row) use ($relatedKeyName) {
return Arr::get($row, $relatedKeyName) === null;
});
$updatedRows = Arr::where($data, function ($row) use ($relatedKeyName) {
return Arr::get($row, $relatedKeyName) !== null;
});
if (count($newRows) > 0) {
$newRecords = $this->createMany($newRows);
$changes['created'] = $castKeys(
$newRecords->pluck($relatedKeyName)->toArray()
);
}
foreach ($updatedRows as $row) {
$this->getRelated()->where($relatedKeyName, $castKey(Arr::get($row, $relatedKeyName)))
->update($row);
}
$changes['updated'] = $castKeys(Arr::pluck($updatedRows, $relatedKeyName));
return $changes;
});
Answer
Solution:
You just need to get the ids from the database and compare
{
$childIds = child::where('parent_id',Request->id)->pluck('id')->toArray();
$flippedChildIds = array_flip($childIds);// we flip the keys and values for easy unsetting.
$childsToBeInsertedOrUpdated = [];
foreach($Request->childs as $item){
//add deleted at in case a child was deleted and need to be re activated
// if you dont want the child to be reactivated, remove "deleted_at" from both arrays
$childsToBeInsertedOrUpdated[] = ['id' => $item->id, 'name' => $item->name, 'deleted_at' => null];
//if exists, remove from the to be deleted childs
unset($flippedChildIds[$item->id]));
}
//only two request for delete and update/create (faster)
if ($flippedChildIds) {
Child::whereIn('id', array_keys($flippedChildIds))->delete();
}
if ($childsToBeInsertedOrUpdated) {
Child::upsert($childsToBeInsertedOrUpdated, ['id'], ['name', 'deleted_at']);
}
}
Source