Create filter in laravel API controller - laravel

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 ]);
}

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.

How to insert into two table using laravel 8? This is my code

This is my code
I have a table inventory_transactions(id, part_name, part_number) and transaction_logs(id, description, inventory_transaction_id(FOREIGN KEY)). I want to insert the value of id to inventory_transaction_id.
What should I do?
namespace App\Http\Controllers;
use App\Models\Inventory_transaction;
use App\Models\Transaction_log;
use Illuminate\Http\Request;
public function store(Request $request){
$inventory_transaction = $request->validate($this->validation());
$value = Inventory_transaction::create($inventory_transaction);
return $this->respondWithMessage('Transaction added');
}
private function validation()
{
return [
'part_name' => ['required'],
'part_number' => ['required'],
];
}
Assuming that you have relationships defined as
class Inventory_transaction extends Model
{
public function transaction_logs()
{
return $this->hasMany(Transaction_log::class);
}
}
you can use the relation to insert related record
public function store(Request $request)
{
$validated = $request->validate($this->validation());
$transaction = Inventory_transaction::create($validated);
$transaction->transaction_logs()->create(['description' => 'Transaction Added.']);
return $this->respondWithMessage('Transaction added');
}
Having said that you should seriously spend some time going through Laravel docs, it will enable you to understand the basics very well - Laravel has one of the best documentation with lots of code examples for easy understanding of basic
Laravel relations: https://laravel.com/docs/8.x/eloquent-relationships#introduction

filter eloquent models in laravel

I have different filters for every category in my blade. when l click on every filter, page URL changes and filter name and filter value shows in URL, like this:
127.0.0.1:8000/categories/search/9?brand[1]=Samsung&brand[2]=Sony&system=android
As you see,every filter can be string or array.
How can I get every filter name in my controller and filter products based on filter name and filter value?
I wrote this conditions ,but these conditions only work if filters that are string, and I don't know how can I write conditions for array filters. This is my controller:
<?php
namespace App\Http\Controllers;
use App\Category;
use App\Filter;
use App\product;
use App\ProductQa;
use Illuminate\Http\Request;
class CategoryController extends Controller
{
public function index(Request $request)
{
$q = product::query();
if ($request->has('brand')) {
$q->where('brand', '=', $request->get('brand'));
}
if ($request->has('system')) {
$q->where('system', '=', $request->get('system'));
}
return $q;
}
}
First define set of filter parameters with their column names, if the filter is array then apply whereIn function else apply where function
public function index(Request $request)
{
$q = product::query();
// ['columnName'=>'GetParamName']
$filters = ['brand'=>'brand','system'=>'system'];
foreach($filters as $column => $key){
if ($request->has($key)) {
$filterVal = $request->input($key)
if(is_array($filterVal)){
$q->whereIn($column, $filterVal);
}else{
$q->where($column,'=', $filterVal);
}
}
}
return $q;
}
As mentioned in the comments you can use whereIn to search with an array of data.
public function index(Request $request)
{
$q = product::query();
if ($request->has('brand')) {
$q->whereIn('brand', (array) $request->input('brand'));
}
if ($request->has('system')) {
$q->whereIn('system', (array) $request->input('system'));
}
...
return $q->get();
}
Casting the input to array, (array), allows us to use only whereIn. If it is already an array you are good and if it is a string it is now in an array. You can also check for an array or a string and use where or whereIn accordingly.

How to restrict whereHas to ONLY match where condition?

I am using Laravel 6.0 and PostgreSQL on Homestead.
This query is returning services which has at least one post with is_assistant = true:
Service::with('posts')
->whereHas('posts', function ($q) {
$q->where('is_assistant', true);
})
->get();
Models:
class Service extends Model
{
public function posts()
{
return $this->belongsToMany('App\Post');
}
}
class Post extends Model
{
protected $casts = [
'is_assistant' => 'boolean',
];
}
How to write an Eloquent query that get services which has ONLY posts with is_assistant = true?
Can use the whereDoesntHave method:
Service::with('posts')
->whereDoesntHave('posts', function ($q) {
$q->where('is_assistant', false);
})
->get();

PhpUnit - mocking laravel model with relations

I'm trying to mock (it's example only) $user->posts()->get().
example service:
use App\Models\User;
class SomeClass{
public function getActivePost(User $user): Collection
{
return $user->posts()->get();
}
}
and my Model:
and Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use \App\Models\Post;
class User extends Model
{
public function posts() : HasMany
{
return $this->hasMany(Post::class);
}
}
this doesn't work:
$this->user = Mockery::mock(User::class);
$this->user
->shouldReceive('wallets->get')
->andReturn('test output');
error:
TypeError: Return value of Mockery_2_App_Models_User::posts() must be an instance of Illuminate\Database\Eloquent\Relations\HasMany, instance of Mockery_4__demeter_posts returned
without return type hint (on post() method) everything is ok. Must I modify andReturn()? idk how
This error can be solved by using the alias prefix with a valid class name. Like the following:
$m = m::mock('alias:App\Models\User');
More information can be found at the official documentation http://docs.mockery.io/en/latest/reference/creating_test_doubles.html#aliasing
Alternatively you can use like this.
use App\Models\User;
class SomeClass{
public function getActivePost(User $user): Collection
{
$user->load('posts');
return $user->posts;
}
}
First you need to mock post, then add it to Collection (don't forget to use it in the top). Then when you call posts attribute its takes mocked $posts. In this case it will not throw error about return type.
use Illuminate\Database\Eloquent\Collection;
$post = $this->mock(Post::class)->makePartial();
$posts = new Collection([$post]);
$this->user = Mockery::mock(User::class);
$this->user
->shouldReceive('getAttribute')
->with('posts');
->andReturn($posts);
Also i wouldn't use mocks here. There is absolutely no need for it. So the unit test i write would be:
Create a user.
Create some posts authored by the user.
Perform assertions on user & posts.
So the code will then be something like this in my test:
$user = factory(User::class)->create();
$posts = factory(Post::class, 5)->create(['user_id' => $user->id]);
$this->assertNotEmpty($user->id);
$this->assertNotEmpty($posts);
$this->assertEquals(5, $posts->fresh()->count());
$this->assertEquals($user->id, $post->fresh()->first()->user_id);
if you want to test the relationship you can:
/** #test */
function user_has_many_posts()
{
$user = factory(User::class)->create();
$post= factory(Post::class)->create(['user_id' => $user->id]);
//Check if database has the post..
$this->assertDatabaseHas('posts', [
'id' => $post->id,
'user_id' => $user->id,
]);
//Check if relationship returns collection..
$this->assertInstanceOf('\Illuminate\Database\Eloquent\Collection', $user->posts);
}

Resources