TitasGailius / nova-search-relations

This package allow you to include relationship columns into Laravel Nova search query.
Other
351 stars 33 forks source link

Nova4 Mysql Error #42

Closed beshoo closed 1 year ago

beshoo commented 1 year ago

"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'attendeds.' in 'where clause' (Connection: mysql, SQL: select * fromattendedswhere ((attendeds.`` like %bash%) or exists (select * fromuserswhereattendeds.user_id=users.idand (users.nameLIKE %bash% orusers.emailLIKE %bash%))) order byattendeds.iddesc,created_atdesc limit 26 offset 0)"

Attended module
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;

use Spatie\MediaLibrary\InteractsWithMedia;

class Attended extends Model implements HasMedia
{
    use InteractsWithMedia;
    protected $fillable = [
        'user_id',
        'presence',
        'leave',
    ];

    protected $casts = [
        'presence' => 'datetime',
        'leave' => 'datetime',
    ];

    public function User(): \Illuminate\Database\Eloquent\Relations\belongsTo
    {
        return $this->belongsTo(User::class);
    }
}

Attended Resource

<?php
User Module
namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use App\Notifications\SendNotification;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\Permission\Traits\HasRoles;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\Translatable\HasTranslations;
class User extends Authenticatable implements JWTSubject, HasMedia
{
    use HasRoles, HasFactory, Notifiable,  InteractsWithMedia , HasTranslations;
    protected $guard_name = 'api';
    public $translatable = ['name'];

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

    /**
     * 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 getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }

    public function sendPasswordResetNotification($token)
    {
        $notification = [
            'subject' => 'Change Your Password',
            'body' => 'We heard that you forgot your password. If you did not make this request, please ignore this email. If you did make this request, please reset your password.',
            'action_title' => 'Change Password',
            'url' => env('APP_URL').'/dashboard/auth/reset_password/?token='.$token,
            'thank_you' => 'Thank you.',
        ];
        $this->notify(new SendNotification($notification));
    }

    public function Attended(): \Illuminate\Database\Eloquent\Relations\HasMany
    {
        return $this->hasMany(Attended::class);
    }

    public function isSuperAdmin()
    {
        //  dd( $this->hasRole('super-admin'));
        return $this->hasRole('super-admin');
    }

    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('avatar_collection')->singleFile()->useDisk('avatar_collection');
        $this->addMediaCollection('image')->singleFile();
        $this->addMediaCollection('gallery');
        $this->addMediaCollection('pdf')->singleFile();
    }

    public function registerMediaConversions(Media $media = null): void
    {
        $this->addMediaConversion('thumb')
            ->width(200)
            ->height(200);
    }

    public function toArray()
    {
        return array_merge(parent::toArray(), ['name' => $this->name]);
    }
}

<?php

namespace App\Nova;

use App\Http\Helper\Helper;
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Laravel\Nova\Actions\Action;
use Laravel\Nova\Actions\ExportAsCsv;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\DateTime;
use Laravel\Nova\Fields\Image;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Nova;
use Laravel\Nova\URL;
use Titasgailius\SearchRelations\SearchesRelations;

class Attended extends Resource
{
    use SearchesRelations;
    /**
     * The model the resource corresponds to.
     *
     * @var class-string<\App\Models\Attended>
     */
    public static $model = \App\Models\Attended::class;
    public static $displayInNavigation = true;

    /**
     * The single value that should be used to represent the resource when being displayed.
     *
     * @var string
     */
    public static $title = 'id';

    /**
     * The columns that should be searched.
     *
     * @var array
     */
    public static $search = [''];
    public static $searchable = true;

    /**
     * Build an "index" query for the given resource.
     *
     * @param \Laravel\Nova\Http\Requests\NovaRequest $request
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public static function indexQuery(NovaRequest $request, $query): \Illuminate\Database\Eloquent\Builder
    {
        $user = $request->user();
        $url = $request->headers->get('referer');
        if ($user?->isSuperAdmin() && !helper::getQueryParamValue($url, 'my_attendance')) {
            // User is a super-admin, return the full query
            return $query->orderBy('created_at', 'DESC');
        } else {
            // User is not a super-admin, return only their own record
            return $query->where('user_id', $user->id)->orderBy('created_at', 'DESC');
        }

    }

    /**
     * Get the fields displayed by the resource.
     *
     * @param \Laravel\Nova\Http\Requests\NovaRequest $request
     * @return array
     */

    public function fields(NovaRequest $request): array
    {

        return [
            // ID::make()->sortable(),
            BelongsTo::make('User')->readonly(function () {
                return $this->resource->exists;
            }),

            Image::make('Profile Photo', 'profile_photo')
                ->thumbnail(function ($value) use ($request) {
                    return $request->user()->getMedia('avatar_collection')->first()?->getUrl();
                })
                ->onlyOnIndex()
                ->rounded(),

            Image::make('Profile Photo', 'profile_photo')
                ->thumbnail(function ($value) use ($request) {
                    return $request->user()->getMedia('avatar_collection')->first()?->getUrl();
                })
                ->onlyOnDetail(),

            DateTime::make('Presence', 'presence')->displayUsing(function ($value) use ($request) {
                // return $value?->format('l / h:i');

                if ($value) {
                    return sprintf('%s', Carbon::parse($value)->setTimezone($request->user()->time_zone ?: 'UTC')->format('l / h:i'));
                }
                return null;

            })->sortable(),

            DateTime::make('Leave', 'leave')->displayUsing(function ($value) use ($request) {
                if ($value) {
                    return sprintf('%s', Carbon::parse($value)->setTimezone($request->user()->time_zone ?: 'UTC')->format('l / h:i'));
                }
                return null;
            })->sortable()->textAlign('center'),

            Text::make('Presence Duration', function () {
                return helper::presenceDuration($this->presence, $this->leave);
            })->textAlign('center'),

        ];
    }

    /**
     * Get the cards available for the request.
     *
     * @param \Laravel\Nova\Http\Requests\NovaRequest $request
     * @return array
     */
    public function cards(NovaRequest $request)
    {
        return [];
    }

    /**
     * Get the filters available for the resource.
     *
     * @param \Laravel\Nova\Http\Requests\NovaRequest $request
     * @return array
     */
    public function filters(NovaRequest $request)
    {
        return [];
    }

    /**
     * Get the lenses available for the resource.
     *
     * @param \Laravel\Nova\Http\Requests\NovaRequest $request
     * @return array
     */
    public function lenses(NovaRequest $request)
    {
        return [];
    }

    /**
     * Get the actions available for the resource.
     *
     * @param \Laravel\Nova\Http\Requests\NovaRequest $request
     * @return array
     */
    public function actions(NovaRequest $request)
    {
        return [
            ExportAsCsv::make()->withFormat(function (\App\Models\Attended $attended) use ($request) {

                return [
                    'Username' => $attended->user->name,
                    'Date' => $attended->presence?->format('Y-m-d'),
                    'PresenceTime' => sprintf('%s', Carbon::parse($attended?->presence)->setTimezone($request->user()->time_zone ?: 'UTC')->format('l / h:i')),
                    'LeaveTime' => $attended?->leave ? sprintf('%s', Carbon::parse($attended?->leave)->setTimezone($request->user()->time_zone ?: 'UTC')->format('l / h:i')) : '--',
                    'WorkTime' => helper::presenceDuration($attended?->presence, $attended?->leave)
                ];
            })->canSee(function ($request) {
                return (bool)($request->user()->isSuperAdmin() || $request->user()->hasRole('admin'));
            }),
        ];
    }

    /**
     * Get the searchable columns for the resource.
     *
     * @return array
     */
    public static function searchableRelations(): array
    {
        return [
            'user' => ['name', 'email'],
        ];
    }

}
beshoo commented 1 year ago

https://nova.laravel.com/docs/4.0/search/#searching-relationships