rappasoft / laravel-livewire-tables

A dynamic table component for Laravel Livewire
https://rappasoft.com/docs/laravel-livewire-tables/v2/introduction
MIT License
1.7k stars 319 forks source link

[Bug]: All relations don't appear inside the collection #1743

Open guarriellocristianmichele opened 1 week ago

guarriellocristianmichele commented 1 week ago

What happened?

<?php

namespace App\Livewire\Customer;

use App\Models\Center;
use App\Models\Customer;
use App\Models\Tag;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Filters\SelectFilter;

class CustomerTable extends DataTableComponent
{
    protected $model = Customer::class;
    public $selectedCustomers = [];

    public function configure(): void
    {
        $this->setPrimaryKey('id');

        $this->setPaginationEnabled();
        $this->setPerPageAccepted([10, 25, 50, 100]);
    }

    public function columns(): array
    {
        $columns = [
            Column::make("Id", "id")
                ->sortable()->searchable(),
            Column::make("Etichetta")->label(fn($row) => $row->tags->pluck('name')->implode(', ')),
            Column::make("Cognome, Nome", "name")
                ->sortable()->searchable(),
            Column::make("Sesso", "sex")
                ->sortable()->searchable(),
            Column::make("Data di nascita", "dob")
                ->sortable()->searchable(),
            Column::make("Codice Fiscale", "tax_code")
                ->sortable()->searchable(),
            Column::make("Telefono", "mobile")
                ->sortable()->searchable(),
            Column::make("Email", "email")
                ->sortable()->searchable()
        ];

        if (auth()->user()->role->value < 3):

            array_unshift($columns, Column::make("Seleziona")->label(
                fn($row, Column $column) => '<input type="checkbox" class="form-checkbox" value="' . $row->id . '"wire:model.live="selectedCustomers">'
            )->html());

            $columns[] = Column::make("Centri")->label(function ($row) {
                dump($row);
            })->sortable()->searchable();
        endif;

        return $columns;
    }

    public function filters(): array
    {
        $cities = Customer::distinct()->get(['location'])->pluck('location', 'location')->toArray();
        $cities = array_merge(['' => 'Seleziona...'], $cities);

        $tags = Tag::query()
            ->orderBy('name')
            ->get()
            ->pluck('name', 'id')
            ->toArray();
        $tags = array_merge(['' => 'Seleziona...'], $tags);

        return [
            SelectFilter::make('Seleziona Città')
                ->options(
                    $cities
                )->filter(function (Builder $builder, string $value) {
                    $builder->where('location', 'like', "%{$value}%");
                }),
            SelectFilter::make('Seleziona Tag')
                ->options(
                    $tags
                )->filter(function (Builder $builder, string $value) {
                    $builder->whereHas('tags', function ($q) use ($value) {
                        $q->where('tag_id', $value);
                    });
                }),

            SelectFilter::make('Con Aziende')
                ->options([
                    '' => 'Seleziona...',
                    '1' => 'Si',
                    '0' => 'No',
                ])->filter(function (Builder $builder, string $value) {
                    if ($value === '1') {
                        $builder->has('companies');
                    } elseif ($value === '0') {
                        $builder->doesntHave('companies');
                    }
                }),
            SelectFilter::make('Con Pagamenti')
                ->options([
                    '' => 'Seleziona...',
                    '1' => 'Si',
                    '0' => 'No',
                ])->filter(function (Builder $builder, string $value) {
                    if ($value == '1') {
                        $builder->whereHas('companies.payments', function ($q) {
                            $q->where('difference', '>', 0)->orWhereNotNull('difference');
                        });
                    } elseif ($value === '0') {
                        $builder->whereHas('companies', function ($q) {
                            $q->doesntHave('payments');
                        });
                    }
                })
        ];

    }

    public function updatedSelectedCustomers()
    {
        $this->dispatch('updated-selected-customers', selectedCustomers: $this->selectedCustomers)->to(CustomerList::class);
    }
}

This is my CustomerTable.

I'm attaching the results of the query and the relations of the model.

Screenshot 2024-06-21 124259

Screenshot 2024-06-21 124228

I'm using Laravel 10.48.14, Livewire 3.5.1, PHP 8.1

How to reproduce the bug

No response

Package Version

3.2.7

PHP Version

8.1.x

Laravel Version

10.48.14

Alpine Version

It's included in the theme so without any sort of reference about what version is being used.

Theme

Tailwind 3.x

Notes

No response

Error Message

No response

lrljoe commented 1 week ago

Okay, so this is actually intentional behaviour!

The package intentionally selects only fields that are actually in use within the table, to avoid deeply nested relations causing issues with load-times/overloading your database.

Which Column/Relationship are you needing to access?

Also just to note, you can use these two methods to either prepend/append a Column to your set of Columns (this is not fully documented/released just yet, but works):

    /**
     * Prepend columns.
     */
    public function prependColumns(): array
    {
        return [];
    }

    /**
     * Append columns.
     */
    public function appendColumns(): array
    {
        return [];
    }

For adding complex relations, you can customise the query in the builder() method to add any relationships that you require, If it's a one-to-one, one-to-many style, then you can use the setAdditionalSelects/addAdditionalSelects (ensuring that you also add in the relevant local/foreign keys), and use the Column as normal.

You can also use a trait that lets you define which relationships you want to add in the configure() method, this is something that will make it into core soon, I just haven't written all of the tests etc just yet!

Do feel free to drop into the official Discord and give me a prod if you need some back/forth etc, as it's normally easier than a diatribe on here!