laraveleloquentlaravel-9laravel-backpacklaravel-backpack-5

Filter by user's company


In the application i'm developing now using Laravel 9 and Backpack for Laravel 5, i have the User model and an Company model with User having many Companies and Company belonging to one User.

A user can add a company to the database and then create invoices, expenses, quotations, employees etc, but basically they are belonging to the company, not the user.

I have added the following line in each controller in the setup() method:

$this->crud->addClause('WHERE', 'company_id', backpack_user()->company_id);

Everything looks like is fine, but in the title of the Clients page let's say, which are the Clients belonging to the Company of the user it states Companies Showing 1 to 1 of 1 entries (filtered from 6 total entries). Reset which makes me believe I did something wrong.

User.php

<?php

namespace App\Models;

use Backpack\CRUD\app\Models\Traits\CrudTrait;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use CrudTrait;
    use HasApiTokens, HasFactory, Notifiable;
    use HasRoles;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'company_id'
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function company() {
        return $this->hasOne(\App\Models\Company::class, 'company_id', 'company_id');
    }
}

Company.php

<?php

namespace App\Models;

use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Company extends Model
{
    use CrudTrait;
    use HasFactory, SoftDeletes;

    /**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public $timestamps = false;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'user_id',
        'company_name',
        'company_registration',
        'company_vat',
        'company_address1',
        'company_address2',
        'company_city',
        'company_postcode',
        'company_created',
        'company_updated',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'company_id' => 'integer',
        'user_id' => 'integer',
        'company_created' => 'datetime',
        'company_updated' => 'datetime',
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function invoice() {
        return $this->hasMany(Invoice::class, 'company_id');
    }

    protected $primaryKey = 'company_id';
}

Client.php

<?php

namespace App\Models;

use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Client extends Model
{
    use CrudTrait;
    use HasFactory, SoftDeletes;

    /**
     * Indicates if the model should be timestamped.
     *
     * @var bool
     */
    public $timestamps = false;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'company_id',
        'client_name',
        'client_registration',
        'client_vat',
        'client_utr',
        'client_cis',
        'client_address1',
        'client_address2',
        'client_address2',
        'client_city',
        'client_postcode',
        'client_country',
        'client_payments_method',
        'client_payments_term',
        'client_country',
        'client_notes',
        'client_created',
        'client_updated',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'client_id' => 'integer',
        'company_id' => 'integer',
        'client_vat' => 'string',
        'client_utr' => 'string',
        'client_cis' => 'boolean',
        'client_country' => 'integer',
        'client_payments_method' => 'integer',
        'client_payments_term' => 'integer',
        'client_created' => 'datetime',
        'client_updated' => 'datetime',
    ];

    public function company()
    {
        return $this->belongsTo(Company::class, 'company_id', 'company_id');
    }

    public function invoices() {
        return $this->hasMany(\App\Models\Invoice::class, 'client_id');
    }

    public function country() {
        return $this->belongsTo(\App\Models\Country::class, 'client_country', 'country_id');
    }

    public function paymentsMethod() {
        return $this->belongsTo(\App\Models\PaymentsMethod::class, 'client_payments_method', 'payments_method_id');
    }

    public function paymentsTerm() {
        return $this->belongsTo(\App\Models\PaymentsTerm::class, 'client_payments_term', 'payments_term_id');
    }

    protected $primaryKey = 'client_id';
}

ClientCrudController.php

public function setup()
    {
        CRUD::setModel(\App\Models\Client::class);
        CRUD::setRoute(config('backpack.base.route_prefix') . '/client');
        CRUD::setEntityNameStrings('client', 'clients');
        CRUD::enablePersistentTable();
        $this->crud->addClause('WHERE', 'company_id', backpack_user()->company_id);

    }

Would you have any pointers on this matter?

Thank you George


Solution

  • You can avoid showing "filtered from 6 total entries" at the top of the ListOperation by using CRUD::addBaseClause() instead of CRUD::addClause(). That will add your clause the the baseQuery. In your case it would be:

    $this->crud->addBaseClause('WHERE', 'company_id', backpack_user()->company_id);
    

    This function wasn't previously documented, so I've added it here - https://backpackforlaravel.com/docs/5.x/crud-operation-list-entries#custom-query-1