Laravel Spatie Searchable - laravel

I am trying to implement spatie searchable in my project and it is working fine when I am doing plain searches. But if I try to do some filtering it is not working and I have no idea though. I have added my code below:
My controller:
<?php
namespace App\Http\Livewire\SuperAdmin;
use Livewire\Component;
use Spatie\Searchable\Search;
use App\Models\Category;
class SuperAdminSearch extends Component
{
public $query;
public $searchResults = [];
public $name = [];
public function updated($property) {
$this->name = $this->categoryName();
if($property == 'query') {
$searchterm = $this->query;
$this->searchResults = (new Search())
->registerModel(Category::class, 'name')
->perform($searchterm);
}
if(empty($this->query)) {
$this->searchResults = [];
}
}
public function render()
{
return view('livewire.super-admin.super-admin-search');
}
}
my model:
protected $fillable = ['name', 'category_type'];
public function getSearchResult(): SearchResult
{
$url = route('super_admin_category_details', $this->id);
return new SearchResult(
$this,
$this->name,
$url
);
}
Now what I want to do is I want to display all the category names where category_type will be ADVERTISEMENT. that's all. But I stuck for this last few days.
Thank you

You have to use SearchAspect. This way you can also search for exact matches and even filter your query like you would using the query builder.
$searchResults = (new Search())
->registerModel(Category::class, function (ModelSearchAspect $modelSearchAspect) {
$modelSearchAspect
->addSearchableAttribute('category_name')
->where('category_type', 'your_category_type_id');
})->perform($searchterm);

Related

Adding key-value to Laravel result object/collection

New to Laravel. Have what seems like should be a non-issue, but is causing a headache.
I'm trying to insert a key-value pair (bookingRef) within the result object/collection returned, such that the result would be:
[{"class_id":7,"class_name":"beginner","class_slots_avail":100,"class_slots_booked":53,"class_date":"2020-12-07 21:47:23","class_time":"09:25:00","class_reg_price":350, bookingRef: 127}]
I've tried methods such as push, put and merge that will insert the key-value after the object returned, but this is not what I require.
Here is my controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Booking;
use App\Http\Controllers\Auth;
use Illuminate\Support\Facades\Mail;
use DB;
class BookingsController extends Controller
{
//
function store(Request $request) {
$id = $request->input('class');
if(DB::table('classes')->where('class_id', '=', $id)->exists()) {
if(DB::table('classes')->where('class_id', '=', $id)->value('class_slots_booked')
< DB::table('classes')->where('class_id', '=', $id)->value('class_slots_avail')) {
$booking = new Booking();
$booking->class_id = $id;
$booking->user_id = \Auth::id();
$booking->save();
DB::table('classes')->where('class_id', '=', $id)->increment('class_slots_booked', 1);
if($booking) {
$confBook = DB::table('classes')->where('class_id', '=', $id)->get();
$confBook->bookingRef = $booking->id;
\error_log($confBook);
}
}
else return('CLASS FULLY BOOOOKED');
}
else return('CLASS NOT Available');
}
}
You can cut down on your queries and put this extra data in place with some adjustments:
function store(Request $request)
{
$id = $rquest->input('class');
$class = DB::table('classes')->where('class_id', $id)->first();
if ($class) {
if ($class->class_slots_booked < $class->class_slots_avail) {
$booking = new Booking();
$booking->class_id = $id;
$booking->user_id = $request->auth()->id;
if ($booking->save()) {
// adding the extra data
$class->bookingRef = $booking->id;
DB::table('classes')->where('class_id', $id)
->increment('class_slots_booked', 1);
$class->class_slots_booked++;
return view('view-booking', [
'bookings' => collect($class),
]);
}
// booking did not save
}
// unavailable
}
// class not found
}
This would be a little more convenient with a Model for the classes table and a relationship setup to Booking would be a plus as well.
I managed to resolve it, thanks to Lagbox's suggestion of using a model:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Booking;
use App\Models\Classes;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
class BookingsController extends Controller
{
//
function store(Request $request) {
$id = $request->input('class');
$class = Classes::where('class_id', $id)->first();
if($class) {
if($class->class_slots_booked < $class->class_slots_avail) {
$booking = new Booking();
$booking->class_id = $id;
$booking->user_id = Auth::id();
if($booking->save()){
$class->where('class_id', $id)->increment('class_slots_booked');
$class->bookingRef = $booking->id;
return view('view-booking', ['bookings' => $class]);
}
}
else return('Class Fully Booked');
}
else return('Class Not Available');
}
};
From what I can see, the get() method returns an array with object(s), which is why object->new_property = value would not work. The first() method, however, seems to return a single object, which is why it would.
Seems I've got some reading up on models and collections to do.

Larave 6 l “Creating default object from empty value”

Here, I have setuo CRUD table with laravel, vuetify and vue . I could successfull create and read data from the database. But, for some reason my update and delete are not working. I am getting error like:
{message: "Creating default object from empty value", exception: "ErrorException",…}
exception: "ErrorException"
file: "C:\WinNMP\WWW\chillibiz\app\Sys\Http\Controllers\StageController.php"
line: 53
message: "Creating default object from empty value"
trace: [{file: "C:\WinNMP\WWW\chillibiz\app\Sys\Http\Controllers\StageController.php", line: 53,…},…]
My code are here:
StageController.php
<?php
namespace App\Sys\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Sys\Model\Stage;
class StageController extends Controller
{
public function index(Request $request)
{
$per_page = $request->per_page ? $request->per_page : 5;
$sort_by = $request->sort_by;
$order_by = $request->order_by;
return response()->json(['stages' => Stage::orderBy($sort_by, $order_by)->paginate($per_page)],200);
}
public function store(Request $request)
{
$uuid = Str::uuid()->toString();
$stage= Stage::create([
'id' => $uuid,
'code' =>$request->code,
'name' =>$request->name,
'description' =>$request->description,
]);
return response()->json(['stage'=>$stage],200);
}
public function show($id)
{
$stages = Stage::where('code','LIKE', "%$id%")->orWhere('name','LIKE', "%$id%")->orWhere('description', 'LIKE', "%$id%")->paginate();
return response()->json(['stages' => $stages],200);
}
public function update(Request $request, $id)
{
$stage = Stage::find($id);
$stage->code = $request->code; //line 53
$stage->name = $request->name;
$stage->description = $request->description;
$stage->save();
return response()->json(['stage'=>$stage], 200);
}
public function destroy($id)
{
$stage = Stage::where('id', $id)->delete();
return response()->json(['stage'=> $stage],200);
}
public function deleteAll(Request $request){
Stage::whereIn('id', $request->stages)->delete();
return response()->json(['message', 'Records Deleted Successfully'], 200);
}
}
Stage.php
<?php
namespace App\Sys\Model;
use Illuminate\Database\Eloquent\Model;
class Stage extends Model
{
protected $guarded = [];
}
I just found they you are using uuid as id not increment. that why you get error like that:
to solve your problem you need to add the field to your model;
<?php
namespace App\Sys\Model;
use Illuminate\Database\Eloquent\Model;
class Stage extends Model
{
public $incrementing = false;
protected $keyType = 'string';
protected $guarded = [];
}
I hope this time you can solve your problem. happy coding.
Edit you can read docs for more info

Getting specific value when using eloquent from Laravel

I am using Laravel 5.2 and I need to get specific values from the database with a leftjoin. The code I am using is as follow:
public function commentList(Request $request)
{
$inputs = $request->all();
$commentList = Comment::select(
'projects_comments.id as comment_id',
'u.name as user_name',
'projects_comments.comment as comment',
'projects_comments.created_at as created_at'
);
$commentList->leftjoin('users AS u', 'projects_comments.user_id', '=', 'u.id');
if (!empty($inputs['project_ids'])) {
$commentList->where(function ($query) use ($inputs) {
foreach ($inputs['project_ids'] as $i) {
$query->orWhere('projects_comments.project_id', $i);
}
});
};
$data = $commentList->get();
return $data;
}
It works fine but I would like to know if there is a better way to do this using eloquent but I can't really understand how to write this for eloquent to work. I need to get all the comments from an array of project ids.
I have the following model for Comment:
class Comment extends Model
{
protected $table = 'projects_comments';
public $timestamps = true;
protected $guarded = ['id'];
public function project()
{
return $this->belongsTo('App\Project', 'project_id');
}
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
}
I assume what you want is to get Comments (with their users) that belongs to specific Projects provided by the user as an array of IDS
Comment::whereIn('project_id', $inputs['project_ids'])->with('user')->get();
And if you only want the id and name of the user associated with the comment, pass the fields to the with function like so
Comment::whereIn('project_id', $inputs['project_ids'])
->with('user:id,name')->get();

Create filter in laravel API controller

Hi i want to create a filter to show mosque with event or activities only. Any idea to display the mosque with activities or events only ?. This one from back-end that later will be fetch using react
namespace App\Http\Controllers;
use App\Event;
use App\Mosque;
use App\Activity;
use Illuminate\Http\Request;
class NotificationController extends Controller
{
public function list()
{
$mosques = Mosque::get();
$array = array();
foreach ($mosques as $mosque) {
array_push($array, [
'mosque_name' => $mosque->name,
'mosque_image'=> $mosque->image
]);
}
return $array;
return response()->json(['result' => $mosques]);
}
public function show(Request $request)
{
$mosque = Mosque::find($request->mosque_id);
$mosque->activities;
$mosque->events;
return response()->json(['result' => $mosque]);
}
}
To filter rows from database, which has particular relationship, you can use whereHas() function on QueryBuilder Instance.
$mosques = Mosque::whereHas('events')
->orWhereHas('activities')
->get();
This function will only returns mosques which has activities or events, other mosques will not fetch.
Also if you only need the name and the image you can filter them too
$mosques = Mosque::whereHas('events')
->orWhereHas('activities')
->get(['name','image']);
You can try this
public function show(Request $request)
{
$mosque = Mosque::find($request->mosque_id);
$mosque->activities;
$mosque->events;
return response()->json(['result' => $mosque->events ]);
}

Laravel: override eloquent function for get results?

I can override function before save :
public function save(array $options = [])
{
if(isset($this->datesConvert)){
foreach($this->datesConvert as $date){
$this->attributes[$date] = Carbon::createFromFormat('d/m/Y', $this->attributes[$date])->format('Y-m-d');
}
}
parent::save($options);
}
But which method I can use for get result ? and where is documentation for this. I am looking for something like :
public function get()
{
parent::get();
if(isset($this->datesConvert)){
foreach($this->datesConvert as $date){
$this->attributes[$date] = Carbon::createFromFormat('Y-m-d', $this->attributes[$date])->format('d/m/Y');
}
}
}
With that I can convert 10 date rows without need of 20 mutators..
It seems that Attribute casting fits your needs or use Date mutators
You may customize which fields are automatically mutated, and even completely disable this mutation, by overriding the $dates property of your model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = [
'created_at',
'updated_at',
'deleted_at',
// more dates
];
}
EDIT
Another way, you can override getAttribute method in Model
<?php
namespace App;
use Carbon\Carbon;
trait DateFormatting
{
protected function dateFields()
{
return [];
}
public function getAttribute($key)
{
if ( array_key_exists( $key, $this->dateFields() ) ) {
return Carbon::createFromFormat('d/m/Y', $this->attributes[$key])->format('Y-m-d');
}
return parent::getAttribute($key);
}
}
then you can use this trait in any your model, just don't forget override dateFields in it
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\DateFormatting;
class User extends Model
{
use DateFormatting;
protected function dateFields()
{
return [
'finished_at',
// other field names that you need to format
];
}
after all you can access to this fields as usual(using magic __get())
$model->finished_at;
I find a solution, My solution is :
public function save(array $options = [])
{
if(isset($this->datesConvert)){
foreach($this->datesConvert as $date){
$this->attributes[$date] = \Carbon\Carbon::createFromFormat('d/m/Y', $this->attributes[$date])->format('Y-m-d');
}
}
parent::save($options);
}
public function getAttribute($key)
{
$value = parent::getAttribute($key);
if(isset($this->attributes[$key])){
if(isset($this->datesConvert) && in_array($key, $this->datesConvert)){
$value = \Carbon\Carbon::createFromFormat('Y-m-d', $value)->format('d/m/Y');
}
}
return $value;
}
Laravel comes with something very useful for this problem. I'm not sure what it's called, but you can modify attributes or even add new attributes like this:
class YourModel extends Model
{
...
public function getDateAttribute()
{
return Carbon::createFromFormat('Y-m-d', $this->attributes[$date])->format('d/m/Y');
}
...
}
You can retrieve this attribute like:
$yourModel->date;
Edit after comment #fico7489
You can't ignore the fact you always have to modify things. However there are still some solutions to make it easier.
For example you can change your date column to a string and just store your date with the desired date format.
Other solution should be modifying the date through sql. FORMAT(Now(),'YYYY-MM-DD').
Example in laravel would look like (not tested):
YourModel::select([
'*',
DB::raw('
FORMAT(yourDateColumn,'YYYY-MM-DD')
')
])->get();

Resources