A BaseClass extends from Eloquent to handle complicated search condition in laravel - laravel

Previous description of my problem is wrong. So I delete it and write a new one.
There are several tables, following are their structures
Table1: id, name
Table2: id, name, date1, date2
Table3: id, name, desc
maybe more tables...
And some html pages, each one references to a table. Every page has one or more search box to search data in related table. I use Ajax to handle the search work. I take some examples as below
Page related table search columns http params
Page1: Table1 id, name q={"id": 1, "name":"bill"}
Page2: Table2 id, date1, date2 q={"id": 1, "date1":"2014-7-19", "date2":"2014-7-20"}
Page3: Table3 id, name q={"id": 1, "name":"bill", "desc":"boss"}
Then I want to create a BaseModel extends from Eloquent, then all other specific Models extends from BaseModel.
I hope there will be a "search" method it can handle all of complicated search actions in BaseModel.

It's hard to suggest a good solution since you don't really tell us, what needs to be done.
This is the most straightforward solution for you, using query scopes:
// BaseModel extending Eloquent Model
public function scopeSearch($query, $jsonSearch)
{
$wheres = $this->parseSearch($jsonSearch);
$query->where($wheres); // WHERE X = Y AND Z = A ...
}
protected function parseSearch($jsonSearch)
{
// validate your input here, make sure it's correct according to your needs
}
Then:
// single result
AnyModel::search($yourJson)->first();
// collection
AnyModel::search($yourJson)->get();
// you can chain more methods if you like
AnyModel::search($yourJson)->where('x', 'y')->orderBy('x')->get();

Related

Laravel whereHas ManyToMany relation but then order by a value in the third table

I have 3 tables
entry (
id,
title,
other_stuff)
entry_award (
id,
award_id,
entry_id)
award (
id,
name,
type)
I am trying to create a laravel query which lets me get all the entries that have awards, and order them by award.type ASC
$Entries = Entry::with('award')
->whereHas('award', function ($query) {
$query->orderBy('award.award_id','ASC');
})->paginate(20);
But this doesn't work.
This is the sql version of it
SELECT DISTINCT entry.*
FROM entry, award, entry_award
WHERE entry.id = entry_award.entry_id
AND award.id = entry_award.award_id
ORDER BY award.type ASC;
Now I tried to just use the raw sql for it, but the problem seems to be that laravel does not then recognize the result as Entry models/objects. And i need to get other Entry relations later on in the html via blade.
So how can I either make a query-builder query that gets me all entries that have awards and orders them by award.type value
or use the raw sql but have Laravel see it as an array of Entry
objects instead of just an array of JSON values.
class Entry extends Model {
public function entry_award(){
return $this->belongsToMany('App\Award', 'entry_award');
}
}
class Award extends Model {
public function entries() {
return $this->belongsToMany('App\Entry', 'entry_award');
}
}

How to retrieve data through model?

I have Order model with another relation OrderPhoto:
public function OrderPhoto()
{
return $this->hasMany('App\OrderPhoto');
}
In turn OrderPhoto model has relation:
public function Photo()
{
return $this->belongsToMany('App\Photo');
}
So, how to get data from OrderModel with related data from third model Photo?
I guess this:
Order::with("OrderPhoto.Photo")->get();
to retrieve only data from Photo model for each Order
So, each Order has some OrderPhotos. Relationship is one to many.
But one item from OrderPhotos is related with primary key from table Photos. It is one to one relation.
My result query should be:
select `photos`.*, `ordersphoto`.`Orders_Id` from `photos` inner join `ordersphoto` on `ordersphoto`.`Photos_Id` = `photos`.`Id` where `ordersphoto`.`Orders_Id` in (1);
How to use hasManyThrough for this query?
Just having a quick look at your relationships it looks like you could create a hasManyThrough relationship on the order Model.
public function Photo {
return $this->hasManyThrough('App\OrderPhoto', 'App\Photo')
}
You may need to add the table keys to make it work
This will allow you to do:
Order::with("Photo")->get();
You can see more details here https://laravel.com/docs/5.5/eloquent-relationships#has-many-through
Update
Try this
public function Photo {
return $this->hasManyThrough('App\Photo', 'App\OrderPhoto', 'Order_id', 'Photos_id', 'id', 'id')
}
It is a little hard to get my head around your DB structure with this info but you should hopefully be able to work it out. This may also help
https://laravel.com/api/5.7/Illuminate/Database/Eloquent/Concerns/HasRelationships.html#method_hasManyThrough

Selecting specific column in ORM relationship Laravel 5.5

I have an order table with a primary key id and another table trips. I trip can have many orders. I have defined the relationship in this way
public function orders_currency() {
return $this->hasMany('App\Order', 'trip_id', 'id')->select('id', 'converted_currency_code');
}
Although I know that, I have to select id of the order table in order to get the result, that's why I am mentioning to select the id of the order table.
Despite this, I am getting the orders_currency index empty. Which angle am I missing in this case?
Any clue will be appreciated.
Did you set up the model correctly?
You'd do something like this in your model script I suppose
class Trips extends Model
{
public function orders() {
return $this->hasMany('Order');
}
I got the solution by doing this way
public function orders_currency() {
return $this->hasOne('App\Order', 'trip_id', 'id')
->select('trip_id','converted_currency_code');
}
I had to select referencing key in this case.

Store relationship with pivot table in laravel 4

Let me explain what i try to achieve.
lets say i have 20 car types for example sport car or family car etc, and 5 cars for example porsche.
When i create a car i have the option to check multiple car types at the same time that belongs to the car and than save it.
I have done some homework and it looks like using a pivot table is the way to go for this inside laravel.
I have this method inside my cars model:
public function types()
{
return $this->belongsToMany('types', 'car_types');
}
And this method inside my types model:
public function cars()
{
return $this->belongsToMany('Car');
}
My tables looks like this:
cars
- id
- name
- created_at
- updated_at
types
- id
- name
- created_at
- updated_at
car_types
- car_id
- type_id
What im trying to do inside my controller is:
$car = new Car();
Car::create( Input::except('types') );
foreach(Input::get('types') as $type)
{
$car->types()->associate($type);
$car->save();
}
This is giving me the following error:
Call to undefined method Illuminate\Database\Query\Builder::associate()
I hope someone can help me out with this.
Thanks in advance.
Well you are almost there. You're right that the two models, Car and Type are in a many to many relation.
In your models you have code that says:
return $this->belongsToMany('types', 'car_types');
and
return $this->belongsToMany('Car');
Error #1:
In the types() method of the Car model as the first parameter you should pass the name of the model, and not the name of the table. So you should change that to something like:
return $this->belongsToMany('Type', 'car_types');
Error #2
In your Car model you're defining the pivot table as car_types, but the pivot definition is missing from the Type model. Either remove , 'car_types' from the types() method in Car model and rename your pivot table to simply car_type, or add , 'car_types' to your cars() method in Type model.
Error #3
Once all the model stuff is set up correctly, you could do in your controller this:
$car = new Car();
$car->name = Input::get('car_name_form_field_name_attribute');
$car->save();
$types = Input::get('types');
$car->types()->sync($types);
Error #4
I'm not sure if this is just a copy/paste error, but your pivot table seems to be missing a primary key field. Every table needs a primary key field, so your car_types table should look something like this:
car_types
id
car_id
type_id
You could also use attach() instead of sync(). More about the difference between these two here
Please try out this code and let us know if it works out.

Use a different column on a many-to-many relationship in Laravel 4

I've got a situation in a project where I need to form a relationship between a primary key on one table and an indexed column (not the primary key) on another. Here's a sample of the database layout:
courses table
id
level
resources table
id
courses_resources table
course_level
resource_id
In my CourseResource model I have the following:
public function courses(){
return $this->belongsToMany('Course', 'courses_resources', 'resource_id', 'course_level');
}
Which works fine.
Then in my Course model I have:
public function resources(){
return $this->belongsToMany('CourseResource', 'course_resources', 'course_level', 'resource_id');
}
Which doesn't work. When I look at the last query performed on the database, it appears Laravel is searching the course_level column using the course's ID. That makes sense, but is there any way to use the level column for this relationship?
Eloquent BelongsToMany depends on PKs, so there is no way to do that with its methods.
You need custom relation object for this, that will check for given field, instead of primary key.
A quick and hacky solution would be this:
// Course model
public function getKey()
{
$relation = array_get(debug_backtrace(1, 2), '1.object', null);
if (method_exists($relation, 'getForeignKey')
&& $relation->getForeignKey() == 'courses_resources.course_level')
{
return $this->getAttribute('level');
}
return parent::getKey();
}
However if you would like to use it in production, do some extensive testing first.

Resources