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