Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Ability to call setRelation (actually anything) for every Model instance. #2862

Open
OzanKurt opened this issue Oct 3, 2022 · 2 comments

Comments

@OzanKurt
Copy link
Contributor

OzanKurt commented Oct 3, 2022

Let me go through it step by step:

1- I extended the default EloquentDataTable and added a method that overwrites the processResults method. This allows me to interact with the DataProcessor object.

<?php

namespace App\DataTables\Engines;

use App\DataTables\Processors\DataProcessor;
use Yajra\DataTables\EloquentDataTable as BaseEloquentDataTable;

class EloquentDataTable extends BaseEloquentDataTable
{
    protected $setRelationsCallback = null;

    public function setRelationsCallback(callable $callable)
    {
        $this->setRelationsCallback = $callable;

        return $this;
    }

    protected function processResults($results, $object = false)
    {
        $processor = new DataProcessor(
            $results,
            $this->getColumnsDefinition(),
            $this->templates,
            $this->request->input('start')
        );

        $processor->setRelationsCallback($this->setRelationsCallback);

        return $processor->process($object);
    }
}

2- I also needed to extend the DataProcessor so that I can customize the process method. This is where we run the callback function we defined for a given model.

<?php

namespace App\DataTables\Processors;

use Yajra\DataTables\Processors\DataProcessor as BaseDataProcessor;
use Yajra\DataTables\Utilities\Helper;

class DataProcessor extends BaseDataProcessor
{
    protected $setRelationsCallback = null;

    public function setRelationsCallback(callable $callable)
    {
        $this->setRelationsCallback = $callable;

        return $this;
    }

    /**
     * Process data to output on browser.
     *
     * @param  bool  $object
     * @return array
     */
    public function process($object = false)
    {
        $this->output = [];
        $indexColumn  = config('datatables.index_column', 'DT_RowIndex');

        foreach ($this->results as $row) {
            $data  = Helper::convertToArray($row, ['hidden' => $this->makeHidden, 'visible' => $this->makeVisible]);

            if ($callback = $this->setRelationsCallback) {
                $callback($row);
            }

            $value = $this->addColumns($data, $row);
            $value = $this->editColumns($value, $row);
            $value = $this->setupRowVariables($value, $row);
            $value = $this->selectOnlyNeededColumns($value);
            $value = $this->removeExcessColumns($value);

            if ($this->includeIndex) {
                $value[$indexColumn] = ++$this->start;
            }

            $this->output[] = $object ? $value : $this->flatten($value);
        }

        return $this->escapeColumns($this->output);
    }
}

3- I think the setRelationsCallback name is wrong, since this gives us the ability to do whatever we want with the Modal instance of every row. Here is what I did with mine:

    public function dataTable($query): DataTableAbstract
    {
        $builder = datatables()->make($query);

        $builder->setRelationsCallback(function (PriceListEntry $priceListEntry) {
            $priceListEntry->setRelation('priceList', $this->priceList);
        });

        // ...
    }

Let me know what you think about this.

I am not sure how useful this might be since it's theoretically just 1 Less Query and 1 Less Model Instance in memory.

@yajra
Copy link
Owner

yajra commented Oct 4, 2022

@OzanKurt I like the idea and this will definitely help in improving our eloquent performance. How about a ->processWith($model) method?

    public function dataTable($query): EloquentDataTable
    {
        $dataTable = new EloquentDataTable($query);

        $dataTable->processWith(function (PriceListEntry $priceListEntry) {
            $priceListEntry->setRelation('priceList', $this->priceList);
        });

        return $dataTable;
    }

@OzanKurt
Copy link
Contributor Author

OzanKurt commented Oct 4, 2022

Sounds great! I will work about this a bit and message here again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants