thedevdojo / voyager

Voyager - The Missing Laravel Admin
https://voyager.devdojo.com
MIT License
11.81k stars 2.67k forks source link

Custom relationship attributes not working #5441

Open yogi-satya opened 3 years ago

yogi-satya commented 3 years ago

Laravel version

8.54

PHP version

7.4.19

Voyager version

1.5

Database

Mysql 5.7.33

Description

I've followed the instructions from https://voyager-docs.devdojo.com/customization/custom-realtionship-attributes , but can't find the attribute in BREAD.

This is my model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class ConstWDesa extends Model
{
    use HasFactory;
    protected $table = 'const_w_desa';
    public $additional_attributes = ['full_wilayah'];

    public function const_w_kecamatan()
    {
        return $this->belongsTo(ConstWKecamatan::class, 'id_kecamatan', 'id');
    }

    public function getFullWilayahAttribute()
    {
        return "{$this->nama_desa} - {$this->const_w_kecamatan->nama_kecamatan} - {$this->const_w_kecamatan->const_w_kabupaten->nama_kabupaten}";
    }
}

This is what BREAD looks like:

Capture

Steps to reproduce

Just follow instructions from https://voyager-docs.devdojo.com/customization/custom-realtionship-attributes

Expected behavior

Want to display 'full_wilayah' instead of column name.

Screenshots

No response

Additional context

No response

yogi-satya commented 3 years ago

I have to change value in database directly to display custom attribute.

Table : data_rows , column : details , in my case i change the value to this :

{
  "label": "full_wilayah",
  "model": "App\\Models\\ConstWDesa",
  "table": "const_w_desa",
  "type": "belongsTo",
  "column": "id_desa",
  "key": "id",
  "pivot_table": "const_w_desa",
  "pivot": "0",
  "taggable": "0"
}

To make search working i have to override controller and edit function relation to this :

    public function relation(Request $request)
    {
        $slug = $this->getSlug($request);
        $page = $request->input('page');
        $on_page = 50;
        $search = $request->input('search', false);
        $dataType = Voyager::model('DataType')->where('slug', '=', $slug)->first();

        $method = $request->input('method', 'add');

        $model = app($dataType->model_name);
        if ($method != 'add') {
            $model = $model->find($request->input('id'));
        }

        $this->authorize($method, $model);

        $rows = $dataType->{$method . 'Rows'};
        foreach ($rows as $key => $row) {
            if ($row->field === $request->input('type')) {
                $options = $row->details;
                $model = app($options->model);
                $skip = $on_page * ($page - 1);

                $additional_attributes = $model->additional_attributes ?? [];

                // Apply local scope if it is defined in the relationship-options
                if (isset($options->scope) && $options->scope != '' && method_exists($model, 'scope' . ucfirst($options->scope))) {
                    $model = $model->{$options->scope}();
                }

                // If search query, use LIKE to filter results depending on field label
                if ($search) {
                    // If we are using additional_attribute as label
                    if (in_array($options->label, $additional_attributes)) {
                        $relationshipOptions = $model->get();
                        $relationshipOptions = $relationshipOptions->filter(function ($model) use ($search, $options) {

                            // THIS IS WHAT I CHANGE
                            if ($options->label == 'full_wilayah') {
                                return stripos($model->nama_desa, $search) !== false;
                            }

                            return stripos($model->{$options->label}, $search) !== false;

                        });
                        $total_count = $relationshipOptions->count();
                        $relationshipOptions = $relationshipOptions->forPage($page, $on_page);
                    } else {
                        $total_count = $model->where($options->label, 'LIKE', '%' . $search . '%')->count();
                        $relationshipOptions = $model->take($on_page)->skip($skip)
                            ->where($options->label, 'LIKE', '%' . $search . '%')
                            ->get();
                    }
                } else {
                    $total_count = $model->count();
                    $relationshipOptions = $model->take($on_page)->skip($skip)->get();
                }

                $results = [];

                if (!$row->required && !$search && $page == 1) {
                    $results[] = [
                        'id'   => '',
                        'text' => __('voyager::generic.none'),
                    ];
                }

                // Sort results
                if (!empty($options->sort->field)) {
                    if (!empty($options->sort->direction) && strtolower($options->sort->direction) == 'desc') {
                        $relationshipOptions = $relationshipOptions->sortByDesc($options->sort->field);
                    } else {
                        $relationshipOptions = $relationshipOptions->sortBy($options->sort->field);
                    }
                }

                foreach ($relationshipOptions as $relationshipOption) {
                    $results[] = [
                        'id'   => $relationshipOption->{$options->key},
                        'text' => $relationshipOption->{$options->label},
                    ];
                }

                return response()->json([
                    'results'    => $results,
                    'pagination' => [
                        'more' => ($total_count > ($skip + $on_page)),
                    ],
                ]);
            }
        }

        // No result found, return empty array
        return response()->json([], 404);
    }
MrCrayon commented 3 years ago

I think to remember the additional attribute will show up only if that model has also BREAD setup.

neurotools commented 2 years ago

Have you tried to add "full_wilayah" to the $additional_attributes array on ConstWDesa model?

public $additional_attributes = ['full_wilayah'];

pckz commented 2 years ago

something new about this? Exactly the same thing happens to me, the custom field does not recognized for BREAD :(

gludovatza commented 2 years ago

Check the BREAD's "Model Name" attribute. Maybe it is the "TCG\Voyager\Models\User", and not your App\Models\User ...

jcalistop commented 2 years ago

Same problem but only with Belong To Many relationship.

Buero7 commented 2 years ago

Same here, with Many to Many after updating to 1.6.

1.5.2. used to work, but issue still remains after downgrading from 1.6 to 1.5.2 (which is curious!)...

This is my model, column full_member not found...

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class dir_member extends Model
{
    const CREATED_AT = 'date_created';
    const UPDATED_AT = 'date_updated';

    public function getFullMemberAttribute($value)
    {
        return "[{$this->id}] {$this->generation_number_id} – {$this->name_first} {$this->name_last} – *{$this->birth_date}";
    }

    public $additional_attributes = ['full_member'];
}

DB:

{
  "foreign_pivot_key":"dir_ps_id",
  "related_pivot_key":"dir_member_family_id",
  "parent_key":"id",
  "model":"App\\dir_member",
  "table":"dir_members",
  "type":"belongsToMany",
  "column":"id",
  "key":"id",
  "label":"full_member",
  "pivot_table":"dir_members_partnerships",
  "pivot":"1",
  "taggable":"0"
}

Laravel 8.83.26 PHP 8.1.8

lamualfa commented 1 year ago

Same problem with Voyager 1.6. It's still not working even after defining the accessor in a new way:

https://laravel.com/docs/9.x/eloquent-mutators#defining-an-accessor

image

image

lamualfa commented 1 year ago

Temporary solution while waiting for PR https://github.com/the-control-group/voyager/pull/5703 to be merged

1. Edit the repositories field on your composer.json to:

{
  "repositories": [
    {
      "type": "vcs",
      "url": "https://github.com/lamualfa/voyager.git"
    }
  ]
}

You can create a new one if the repositories field doesn't exist.

2. Edit the tcg/voyager version on your composer.json to dev-fix-5441:

{
  "require": {
    "tcg/voyager": "dev-fix-5441"
  }
}

The dev-fix-5441 means that you tell the composer to install tcg/voyager from https://github.com/lamualfa/voyager/tree/fix-5441 instead.

3. Run composer update to update the tcg/voyager package.

The final composer.json file will looks like this:

{
  "repositories": [
    {
      "type": "vcs",
      "url": "https://github.com/lamualfa/voyager.git"
    }
  ],
  "require": {
    "tcg/voyager": "dev-fix-5441"
  }
}

References

Buero7 commented 1 year ago

@lamualfa seems to work fine, thank you!

skarjoss commented 1 year ago

I think to remember the additional attribute will show up only if that model has also BREAD setup.

@MrCrayon This worked for me, the related table must have a BREAD, only then the relationship attributes are listed. The docs should mention this.

This behavior is defined in VoyagerDatabaseController.php#L248