'Using Repository in edit method Repository is null

With laravel 7 /livewire app I make crud using Repository and I got listing of data ok, In mount event I assign protected var $FacilityRepository , which works ok in render method,

but it is null in edit method and I got error:

Call to a member function getById() on null

when user clicks on “edit link”

<?php

namespace App\Http\Livewire\Admin;

use App\library\CheckValueType;
use App\Settings;
use DB;
use Livewire\Component;
use App\Facility;
use Livewire\WithPagination;
use App\Repositories\Interfaces\FacilityRepositoryInterface;


class Facilities extends Component
{
    use WithPagination;

    public $form= [
        'name'=>'',
        'descr'=> '',
        'created_at'=> '',
        'is_reopen'       => false,
    ];

    public $current_facility_id;
    public $filter_name= '';
    public $updateMode = 'browse';

    protected $FacilityRepository;
    public function render()
    {
        $this->facility_rows_count = Facility
            ::getByName($this->filter_name, true)
            ->count();
        $backend_per_page = Settings::getValue('backend_per_page', CheckValueType::cvtInteger, 20);
        \Log::info( 'render -10 $this->FacilityRepository::' . print_r(  json_encode($this->FacilityRepository), true  ) );
        // line above logged as : [2020-09-04 16:46:26] local.INFO: render -10 $this->FacilityRepository::{}

        return view('livewire.admin.facilities.container', [
            'facilityDataRows' => $this->FacilityRepository->filterWithPagination(
                [
                    'name'=>$this->filter_name,
                ],
                $backend_per_page
            ),
            'facility_rows_count'=> $this->facility_rows_count
        ]); // this listing is rendered OK
    }


    public function mount(  FacilityRepositoryInterface $FacilityRepository  ) {
        $this->FacilityRepository = $FacilityRepository;
        \Log::info( '-101mount $this->FacilityRepository::' . print_r(  json_encode($this->FacilityRepository), true  ) );
        // line above logged as : [2020-09-04 16:46:26] local.INFO: -101mount $this->FacilityRepository::{}
    }


    public function edit($id)
    {
        \Log::info( '-1 edit $id::' . print_r(  json_encode( $id ), true  ) );
        \Log::info( '-1 edit $this->FacilityRepository::' . print_r( $this->FacilityRepository, true  ) );
        // line above logged as : [2020-09-04 16:46:28] local.INFO: -1 edit $this->FacilityRepository::
        // AND ERROR NEXT
        $this->form = $this->FacilityRepository->getById($id)->toArray();
        \Log::info( '-1023 $this->form ::' . print_r(  json_encode( $this->form ), true  ) );


        $this->current_facility_id = $id;
        $this->form['created_at'] = getCFFormattedDateTime($this->form['created_at']);
        $this->emit('facility_opened',[ 'mode'=>'edit', 'id'=>$id ]);
        $this->updateMode = 'edit';
    }

In template edit link is defined as :

@foreach($facilityDataRows as $nextFacilityDataRow)
    <tr>
        <td class="text-right m-0">
            <a wire:click="edit({{$nextFacilityDataRow->id}})"
                class="p-1 a_edit_item_{{$nextFacilityDataRow->id}} a_link">
                {{$nextFacilityDataRow->id}}
            </a>
        </td>

...

Why error and how to fix it ?

Modified # 2:

  1. If I make

    class Facilities extends Component { ... public $FacilityRepository; }

I got error :

Livewire component's [admin.facilities] public property [FacilityRepository] must be of type: [numeric, string, array, null, or boolean]. Only protected or private properties can be set as other types because JavaScript doesn't need to access them.
  1. I tried to declare method edit as :

    public function edit( FacilityRepositoryInterface $facilityRepository, int $id) { // Did you mean this ? ... }

I got error :

Call to a member function filterWithPagination() on null

on method filterWithPagination, which is used in render method, when I show listing of data. Which way is correct ?

Modified # 3: If to modify :

public function render(FacilityRepositoryInterface $facilityRepository)
{

I got error :

Declaration of App\Http\Livewire\Admin\Facilities::render(App\Repositories\Interfaces\FacilityRepositoryInterface $facilityRepository) should be compatible with Livewire\Component::render()

?

Modified # 4: Opening page in mode I have 2 inputs with lazy defined, like

            <dd class="horiz_divider_right_23" wire:model="form.title.lazy" x-data="{ name: '{{$form['name']}}'}">
                
                <input
                    x-model="name"
                    x-on:blur="$dispatch('name', name)"
                    id="name"
                    class="form-control editable_field admin_control_input"
                    placeholder="Enter descriptive name"
                    autocomplete=off
                >
                @error('form.name')
                <div class="validation_error">{{ clearValidationError($message,['form.'=>'']) }}</div> @enderror
            </dd>

and when I edit some of fields on blur ervent I got the same error :

Call to a member function filterWithPagination() on null

with url in error description :

VM5783:1 POST http://local-hostels3.com/livewire/message/admin.facilities 500 (Internal Server Error)

where http://local-hostels3.com is my local hosting

Have I in some way to overrride message method ?

"laravel/framework": "^7.0",
"livewire/livewire": "^1.3",

Thanks!



Solution 1:[1]

protected and private properties DO NOT persist between Livewire updates. In general, you should avoid using them for storing state.

https://laravel-livewire.com/docs/properties/#important-notes

That being said, you can use dependency injection again, just pass whatever you need (FacilityRepositoryInterface in this case) as the first argument(s) of the edit method.

Same applies to the render method, so you can skip mount altogether.

Correction

The last bit in my original answer is wrong, you cannot use DI in the render method.

So for use in render, use the mount method and for use in edit, bring it via the first parameter. If render complains about not having it after usage of edit, save to the protected property inside edit as well.

Final code, that should work


class Facilities extends Component
{
  protected $FacilityRepository;

  public function mount(FacilityRepositoryInterface $FacilityRepository)
  {
    $this->FacilityRepository = $FacilityRepository;
  }

  public function render()
  {
    // use $this->FacilityRepository->...
  }

  public function edit(FacilityRepositoryInterface $FacilityRepository, $id)
  {
    $this->FacilityRepository = $FacilityRepository;
    // rest of the edit method from your code
  }
}

Solution 2:[2]

add boot method

public function boot(FacilityRepositoryInterface $FacilityRepository)
{
    $this->FacilityRepository = $FacilityRepository;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Mohammadmahdi Khakdaman