title: Define fields based on resource's model attributes in Laravel Nova
body: <p>I have a (relatively) basic need in Nova that I can't seem to figure out and I slowly start to feel that I'm approaching things the wrong way.
  So, I've got a <code>User</code>, <code>Company</code>, <code>Device</code> and <code>Transfer</code> models and respectively resources, everything pretty default regarding the resource setup.
  The schema is the following:</p>
  <ul>
  <li><code>users</code>: <code>id, company_id</code></li>
  <li><code>companies</code>: <code>id, type_id, name</code> where <code>type_id</code> is pointing to one of three pre-populated types (manufacturer, dealer, client)</li>
  <li><code>devices</code>: <code>id, imei</code></li>
  <li><code>transfers</code>: <code>id, from_company_id, to_company_id, accepted_at</code></li>
  <li>and <code>Transfer</code> is in a Many-to-Many with <code>Device</code>.</li>
  </ul>
  <p>The idea behind the transfers being that Manufacturers transfer to Dealers, Dealers transfer to Clients, so it's really only a one-way thing.</p>
  <p>Now the problem occurs at the following crucial point in the logic:
  In my <code>Transfer</code> resource pages, I want to show different fields depending on the type of the company the currently authenticated user belongs to. Basically, if the company is:</p>
  <ul>
  <li>Manufacturer, then display a <code>DEALER</code> column populated with the transfers' <code>toCompany</code> relation;</li>
  <li>Dealer, then display a <code>CONTRAGENT</code> column populated with the transfers' <code>fromCompany</code> or <code>toCompany</code> relations (depending on which mathces the current auth() company)</li>
  <li>Client, then display a <code>DEALER</code> column populated with the transfers' <code>fromCompany</code></li>
  </ul>
  <p>All of the described logic works fine with the following code (<code>App\Nova\Transfer.php</code> as is) UNTIL I wanted to finally display the transfer's devices on the details page:</p>
  <pre><code>&lt;?php
  
  namespace App\Nova;
  
  use Illuminate\Http\Request;
  use Laravel\Nova\Fields\ID;
  use Laravel\Nova\Fields\BelongsTo;
  use Laravel\Nova\Fields\BelongsToMany;
  use Laravel\Nova\Http\Requests\NovaRequest;
  
  class Transfer extends Resource
  {
      public static $model = \App\Models\Transfer::class;
  
      public static $title = 'id';
  
      public static $search = [
          'id',
      ];
      
      public static $with = [
          'fromCompany',
          'toCompany'
      ];
  
      public function fields(Request $request)
      {
          $company = auth()-&gt;company();
          
          if($company-&gt;hasType('manufacturer'))
          {
              $contragentTitle = 'Dealer';
              $contragent = 'toCompany';
          } 
          else if($company-&gt;hasType('dealer'))
          {
              //\Debugbar::info($this); //showing empty resource when populating the devices
              $contragentTitle = 'Contragent';
              $contragent = $this-&gt;fromCompany-&gt;is($company) ? 'toCompany' : 'fromCompany'; //exception here, since the resource is empty and fromCompany is null
          } 
          else
          {
              $contragentTitle = 'Dealer';
              $contragent = 'fromCompany';
          }
          
          $contragentCompanyField = BelongsTo::make(&quot;$contragentTitle company&quot;, $contragent, Company::class);
          
          if($company-&gt;hasType('dealer'))
          {
              $contragentCompanyField-&gt;displayUsing(function ($contragentCompany) use ($contragent){
                  return $contragentCompany-&gt;title() . &quot; (&quot;.($contragent == 'toCompany' ? 'Outgoing' : &quot;Incoming&quot;).')';
              });
          }
          
          return [
              ID::make(__('ID'), 'id')-&gt;sortable(),
              $contragentCompanyField,
              BelongsToMany::make('Devices') //problematic field, when removed, everything is fine...
          ];
      }
      
      public static function indexQuery(NovaRequest $request, $query)
      {
          if(auth()-&gt;check())
          {
              return $query-&gt;where(function($subQuery){
                  return $subQuery-&gt;where('from_company_id', auth()-&gt;company()-&gt;id)-&gt;orWhere('to_company_id', auth()-&gt;company()-&gt;id);
              });
          }
      }
  
      public function cards(Request $request)
      {
          return [];
      }
  
      public function filters(Request $request)
      {
          return [];
      }
  
      public function lenses(Request $request)
      {
          return [];
      }
  
      //action is working fine (additional canRun added to avoid policy conflicts)
      public function actions(Request $request)
      {
          return [
              (new Actions\AcceptTransfer())-&gt;showOnTableRow()-&gt;canSee(function ($request) {
                  if ($request instanceof \Laravel\Nova\Http\Requests\ActionRequest) {
                      return true;  
                  }
                  
                  return $this-&gt;resource-&gt;exists
                          &amp;&amp; $this-&gt;resource-&gt;toCompany-&gt;is(auth()-&gt;company())
                          &amp;&amp; $this-&gt;resource-&gt;accepted_at === null;
                  
              })-&gt;canRun(function ($request) {
                  return true;
              })
          ];
      }
  }
  
  </code></pre>
  <p>Now the strange thing that is happening is that the <code>fields()</code> method gets called multiple times on multiple ajax requests behind the scenes with Nova and when populating the devices relationship table, it gets called without a resource, although a call is never actually needed (as far as I can grasp the mechanics behind Nova) or at least when fetching relationships, you must still have the model information (at least the ID) somewhere to fetch by... So basically, if I'm a user of a dealer company, I can't see the devices that are being transferred (currently throwing a <code>calling is() on null</code> exception).</p>
  <p>Now, this happens to be a big problem, since it hinders most of the stuff I need for my transfers, but also generally I don't like my approach so far, so... What would be the right way to achieve this <code>multi-layer</code> resource? Ideally I'd like to define three different transfer resource classes and somehow tell nova which one to use based on the user's company's type (since branching will most probably just grow more complex and therefore uglier as of the current aproach), but I can't figure out the way to do so.</p>
  <p>I've also considered moving this entire logic to a separate Nova tool, but I really don't know much about them yet and whether that would be the right option... The only thing stopping me is that I still won't be able to elegantly solve the multi-layer problem and will have to write much of the otherwise useful Nova CRUD logic and views myself...</p>
  <p>Any explanations (regarding the multiple calls of <code>fields()</code> and why resource is empty) or general structural recommendations to solve this case would be greatly appreciated! Many thanks in advance!</p>
  <p><strong>EDIT:</strong>
  I was able to circumvent the error by taking advantage of <code>viaResourceId</code>, so instaed of <code>$this</code> I ended up using:</p>
  <pre><code>$transfer = $this-&gt;id ? $this-&gt;resource : \App\Models\Transfer::find($request-&gt;viaResourceId);
  </code></pre>
  <p>but the messy code and the unneeded calls still remain an open question. Thanks again in advance!</p>