Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Sharim's avatar

Call to a member function related() on null

I'm trying to delete products in bulk but I'm getting this error:

Call to a member function related() on null

but Single item delete is working.

Delete Method:

public function destroy(Request $request, $id)
    {
        $slug = $this->getSlug($request);

        $dataType = Voyager::model('DataType')->where('slug', '=', $slug)->first();

		//delete related items
        $product = Product::where('id', $id)->first();
        $product->related()->sync($request->related_id);
        

        // Init array of IDs
        $ids = [];
        if (empty($id)) {
            // Bulk delete, get IDs from POST
            $ids = explode(',', $request->ids);
        } else {
            // Single item delete, get ID from URL
            $ids[] = $id;
        }
        foreach ($ids as $id) {
            $data = call_user_func([$dataType->model_name, 'findOrFail'], $id);

            // Check permission
            $this->authorize('delete', $data);

            $model = app($dataType->model_name);
            if (!($model && in_array(SoftDeletes::class, class_uses_recursive($model)))) {
                $this->cleanup($dataType, $data);
            }
        }

        $displayName = count($ids) > 1 ? $dataType->getTranslatedAttribute('display_name_plural') : $dataType->getTranslatedAttribute('display_name_singular');

        $res = $data->destroy($ids);

        

        return redirect()->back()->with($data);
    }
0 likes
16 replies
Sinnbeck's avatar

Use findOrFail to make sure you get a record

$product = Product::findOrFail($id);
Sharim's avatar

@Sinnbeck I think id = 0 in bulk delete. That is a controller of voyager admin panel. There is 2 different conditions from single item and bulk items like this:

$ids = [];
        if (empty($id)) {
            // Bulk delete, get IDs from POST
            $ids = explode(',', $request->ids);
        } else {
            // Single item delete, get ID from URL
            $ids[] = $id;
        }
        foreach ($ids as $id) {
            $data = call_user_func([$dataType->model_name, 'findOrFail'], $id);

            // Check permission
            $this->authorize('delete', $data);

            $model = app($dataType->model_name);
            if (!($model && in_array(SoftDeletes::class, class_uses_recursive($model)))) {
                $this->cleanup($dataType, $data);
            }
        }
Sinnbeck's avatar

@Sharim But isnt this your code?

//delete related items
        $product = Product::where('id', $id)->first();
        $product->related()->sync($request->related_id);

If that is supposed to bulk delete you need to get multiple items (all I assume?)

Sharim's avatar

@Sinnbeck Yes this code is working on single item delete only but not in bulk delete.

Sinnbeck's avatar

@Sharim Yes. You are doing the bulk logic after you have gotten the product.. Maybe you meant to put it after?

$products = Product::whereIn('id', $ids)->get();
$products->each->related()->sync($request->related_id);
Sharim's avatar

@Sinnbeck You mentioned two different variables $products & $product. It'll work ?

Sharim's avatar

@Sinnbeck Getting this error:

Method Illuminate\Database\Eloquent\Collection::sync does not exist.

Sharim's avatar

@Sinnbeck I put this code after foreach:

$products = Product::whereIn('id', $ids)->get();
$products->each->related()->sync($request->related_id);
Sharim's avatar

@Sinnbeck here is the full method sir:

public function destroy(Request $request, $id)
    {
        $slug = $this->getSlug($request);

        $dataType = Voyager::model('DataType')->where('slug', '=', $slug)->first();
        
        // Init array of IDs
        $ids = [];
        if (empty($id)) {
            // Bulk delete, get IDs from POST
            $ids = explode(',', $request->ids);
        } else {
            // Single item delete, get ID from URL
            $ids[] = $id;
        }
        foreach ($ids as $id) {
            $data = call_user_func([$dataType->model_name, 'findOrFail'], $id);

            // Check permission
            $this->authorize('delete', $data);

            $model = app($dataType->model_name);
            if (!($model && in_array(SoftDeletes::class, class_uses_recursive($model)))) {
                $this->cleanup($dataType, $data);
            }
        }

        $products = Product::whereIn('id', $ids)->get();
        $products->each->related()->sync($request->related_id);

        $displayName = count($ids) > 1 ? $dataType->getTranslatedAttribute('display_name_plural') : $dataType->getTranslatedAttribute('display_name_singular');

        $res = $data->destroy($ids);
        
        $data = $res
            ? [
                'message'    => __('voyager::generic.successfully_deleted')." {$displayName}",
                'alert-type' => 'success',
            ]
            : [
                'message'    => __('voyager::generic.error_deleting')." {$displayName}",
                'alert-type' => 'error',
            ];

        if ($res) {
            event(new BreadDataDeleted($dataType, $data));
        }

        return redirect()->back()->with($data);
    }
Sinnbeck's avatar
Sinnbeck
Best Answer
Level 102

@Sharim Weird that should work! I dont understand why you are getting that error. Can you try the old way?

$products = Product::whereIn('id', $ids)->get();
foreach ($products as $product) {
    $product->related()->sync($request->related_id);
}

Please or to participate in this conversation.