Laravel sort with eager loading - laravel-4

In Laravel 4.2, we have a User:: model, which has Message::(s). Every Message has a Sender:: which is not a normal user. I want to sort the result dynamically by columns in Sender:: model.
I have tried this but it doesn't work:
$this->sort->dir = 'asc';
$this->sort->by = 'sender_name';
$result = User::find(1)->messages()->with(array('sender' => function($query){
$query->orderBy($this->sort->by , $this->sort->dir );
}))->paginate(10);
User Class:
class User extends Eloquent{
....
public function messages(){
return $this->hasMany('Message' , 'toid' , 'id' );
}
Message Class:
class Message extends Eloquent{
....
public function sender(){
return $this->hasOne('Sender' , 'sender_id' , 'fromid' );
}
Message Table:
id, toid, fromid, text
Sender Tabele:
sender_id, sender_name, ...
User Table:
id,name,....
I can't change the table structure as it is related to another application. Does anybody know what is wrong here?

you are almost near, just you need little modification, pass variable in closure and add get() at the end of orderBY to get records in your desire orders.
$by = 'sender_name';
$dir= 'asc';
$result = User::find(1)
->messages()
->with(array('sender' => function($query) use($by, $dir){
$query->orderBy(by , $dir )->get();
}))->paginate(10);

Related

inner join table (inverse) using larvel eloquent

Im new to this laravel eloquent so bare with me. Im doing a search function for Payment. everything is doing fine, until i need to inner join a table Contract for me to output $payment->contract->account_no in a search result.
i just need to convert this SQL to eloquent (i only included account_no since its the column that i need get in Contract)
SELECT
tbt_contracts.account_no , tbt_payments.payment_type, tbt_payments.payment_mode, tbt_payments.payment_date, tbt_payments.payment_amount, tbt_payments.payment_due_date,
tbt_payments.payee_name
FROM tbt_payments
INNER JOIN tbt_contracts ON tbt_payments.contract_id = tbt_contracts.id
WHERE tbt_contracts.account_no LIKE '%test%'
Payment Model
public function contract()
{
return $this->belongsTo(Contract::class);
}
Contract Model
public function payments()
{
return $this->hasMany(Payment::class);
}
Payment Controller (when i click the search button)
$filters = [];
//account_no (ERROR)
!is_null($request->account_no) ? array_push($filters, ['account_no', 'like','%'.$request->account_no.'%']) : null;
//payment_type
!is_null($request->payment_type) ? array_push($filters, ['payment_type', 'like','%'.$request->payment_type.'%']) : null;
//payment_mode
!is_null($request->payment_mode) ? array_push($filters, ['payment_mode', 'like','%'.$request->payment_mode.'%']) : null;
//payee_name
!is_null($request->payee_name) ? array_push($filters, ['payee_name', 'like','%'.$request->payee_name.'%']) : null;
return view('transaction.payment.paymentlist', [
'payments' => Payment::where($filters)->orderBy('id')->paginate(10),
'payment_modes' => LogicCONF::getDropDownJson('payment_mode.json'),
'payment_types' => LogicCONF::getDropDownJson('payment_type.json'),
]);
working code (works without table join, errors with table join)
return view('transaction.payment.paymentlist', [
'payments' => Payment::where($filters)->orderBy('id')->paginate(10),
]);
DB Facade:
I tried DB Facade. my problem with it is i cannot use or call Public Function inside my payment model. (i haven't even tried joining the tables)
$payments = DB::table("tbt_payments")->orderBy('id')->paginate(10);
done.
for some reason innerjoin dont work,
also thanks to this SQLtoEloquent
$payments = Payment::with("contract")
->leftJoin("tbt_contracts", function($join){
$join->on("tbt_payments.contract_id","tbt_contracts.id");
})
->where($filters)
->select('tbt_payments.*')
// ->groupBy("tbt_payments.id")
->orderBy('tbt_payments.id')
->paginate(10);

Laravel Eloquent is there a better way to write this query?

I have a typical pivot table structure like this:
Users
id [...]
Locations
id [...]
User_Location
id | user_id | location_id
I need to get the locations the current authorized user has access to, and then I need to get all the users who also have access to all of those locations.
I tried to figure out an "eloquent" way to do this, but I'm not familiar enough with it. This works, but I'm wondering if it's the best way to do it?
$locations = auth()->user()->locations(); //returns the user_location records
$locationIds = $locations->pluck('location_id');
$locationUsers = new UserLocation();
$userIds = $locationUsers->whereIn('location_id', $locationIds)->groupBy('user_id')->pluck('user_id');
$users = User::withTrashed()
->whereIn('id', $userIds)
->get();
return view('users.index')->with('users', $users);
here's the locations() relationship referenced in the code:
public function locations()
{
return $this->belongsToMany(Location::class, 'user_location')->withPivot('primary');
}
You must create a new method in the Locations model.
public function users()
{
return $this->belongsToMany(User::class, 'user_location');
}
Then your query could look like this.
$locations = auth()->user()->locations()->with('users')->get();
$users = $locations->pluck('users');
If you need to get all users withTrashed then you should modify the first line for this.
$locations = auth()->user()->locations()->with(['users' => function ($user) {
$user->withTrashed();
}])->get();

Get values from relationship Laravel

I have a query where I get values from 3 tables, for first 2 I use leftJoin, and is Ok, but for third one I try to get an array of objects, and I am not sure how.
In relationship table a have multiple rows for each ID from People table. HasMany type.
$q = Person::leftJoin('registers', 'people.register_id', '=', 'registers.id')
->leftJoin('relationships', 'people.id', '=', 'relationships.person_id') //if I comment this it works for first 2 tables
->find($id);
return response()->json($q);
Person
public function relationship()
{
return $this->hasMany(Relationship::class);
}
public function register()
{
return $this->belongsTo(Register::class);
}
Relationship
public function person()
{
return $this->belongsTo(Person::class, 'person_id');
}
Register
public function people(){
return $this->hasOne(Person::class);
}
UPDATE -> this works,but is kind of ugly, I think that should be a better way in Laravel
$q = Person::leftJoin('registers', 'people.register_id', '=', 'registers.id')
->find($id);
$q2 = Person::find($id)->relationship;
return response()->json([
'values' => $q,
'relationship' => $q2,
]);
You can just use with like this:
Person::with(['register', 'relationship'])->find($id);

mb_strpos() expects parameter 1 to be string, object given when querying 2 tables in Laravel

Ok, so I don't know if this can be done, but I need to combine the results of 2 Where clauses from 2 tables into one variable.
So far I have this working to query one table:
$allCompanies = Products::where('category_id', $id->id)->groupBy('company_id')->get();
And this for the other:
$companies = Company::where('visible', 0)->get();
But is there any way to get them into the same query string? Something like so I can get where the ID matches the ID column in one table AND where visible is 0 in the other?
I tried this:
$allCompanies = Products::with('company', function($q){
$q->where('visible', 0);
})->where('category_id', $id->id)
->groupBy('company_id')->get();
but got this error:
mb_strpos() expects parameter 1 to be string, object given
Company Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
public function products()
{
return $this->hasMany('App\Products');
}
}
Products Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Products extends Model
{
protected $fillable = [
'name',
'description',
'image',
'size',
'price',
'stock',
'company_id',
'category_id'
];
public function category()
{
return $this->belongsTo('App\Categories', 'category_id');
}
public function company()
{
return $this->belongsTo('App\Company', 'company_id');
}
}
When using callback in with, you should pass callback as value of associative-array.
Your query should be:
$allCompanies = Products::with(['company' => function($q) {
$q->where('visible', 0);
}])
->where('category_id', $id->id)
->groupBy('company_id')
->get();
Ref: https://laravel.com/docs/8.x/eloquent-relationships#nested-eager-loading-morphto-relationships
The most Laravel way of achieving this is through Relationships and whereHas. If you have a relationship defined you could do the following:
$products = Products::where('category_id', $id->id)
->whereHas('company', function($q) {
$q->where('visible', 0);
});
Which will query for all the products with a certain category_id that also have a relationship with a company that has a column visible with value 0
Depends on what you want:
If you want all the products from visible companies:
$products = Products::whereHas('company', function($q) {
$q->where('visible',0);
})->get();
If you want all the companies with their products (which I would advise):
$Companies = Company::with('products')->where('visible',0)->get();

How can i decode json data if i saved in array laravel?

I have 2 two tables: one is an admission and the other is a class table. I am saving class id in admission class field of admission table by json_encode method.
My controller
public function store(Request $request)
{
$inputs = $request->all();
$admission = new Admission;
$admission->school_id = Auth::User()->id;
$admission->admission_classes=json_encode($inputs['admission_classes']);
$admission->save();
}
My index function
public function index(Request $request) {
$school_id= Auth::user()->id;
$admissions= Admission::where('school_id',$school_id)->orderBy('id','desc')->paginate(10);
return view('frontend.index',compact('admissions','active_class'));
}
My view
#foreach($admissions as $i => $admission)
{{ $admission->admission_classes }}
#endforeach
I am getting data in this way:-
["1","2","4","5","6","7","8","9"]
But I want to get in this format:
Nursery,Class 1, Class2, Class3 etc
My class controller
class Classes extends Authenticatable
{
use EntrustUserTrait;
use Billable;
use Messagable;
protected $fillable = [
'name','status'
];
}
You need to save integer value in as json array and do the following code
$integerIDs = array_map('intval', $inputs['admission_classes']);
$admission->admission_classes= json_encode($integerIDs);
public function index(Request $request){
$admissions = DB::select('SELECT a.*, GROUP_CONCAT(c.name) as classes FROM academy as a LEFT JOIN class c ON JSON_CONTAINS(a.classes, CAST(c.id as JSON), '$') WHERE a.school_id =2 GROUP BY a.id');
$admissions = $this->arrayPaginator($admissions, $request);
return view('frontend.index',compact('admissions','active_class'));
}
public function arrayPaginator($array, $request)
{
$page = Input::get('page', 1);
$perPage = 10;
$offset = ($page * $perPage) - $perPage;
return new LengthAwarePaginator(array_slice($array, $offset,
$perPage, true), count($array), $perPage, $page,
['path' => $request->url(), 'query' => $request->query()]);
}
I have not checked the code hope this will help u to continue.......
The best way to achieve this would be to have a one-to-many relationship with App\Classes.
However, since you already have something up and running, I would probably do it like this.
First, I would cast admission_classes to an array. This makes sure that admission_classes will always be casted to an array whenever it is fetched. It makes it easier for us to work with it.
protected $casts = [
'admission_classes' => 'array'
];
Finally, while fetching your admission records, you would also need to map over it and hydrate the Classes from its ids. This is how I'd try to achieve it.
$admissions = Admission::where('school_id',$school_id)
->orderBy('id','desc')
->paginate(10)
->map(function($admission) {
return array_map(function($class) {
$class = Classes::find($class);
return isset($class) ? $class->name : '';
}, $admission->admission_classes);
});
You will notice that I wrapped the Classes::find() method into the optional() helper. This is because, in case, a record is not found, it will not fail.
Finally, to print your class names in your blade, you would do something like this:
implode(',', $admission->admission_classes);

Resources