associate() and 1tomany strange behavior - laravel

im using Laravel 5.3 and ive a simple controller with a "store" method, this is the "belongTo" side of the relations.
The others 2 models contain correctly the "hasMany" function.
public function store(Request $request)
{
$user_id = JWTAuth::parseToken()->authenticate()->id;
if(!Vehicle::where('id', '=', $request->vehicle_id)->exists()){
return $this->response->error('could_not_create_trip_errore_veicolo', 500);
}
if(!Ztl::where('id', '=', $request->ztl_id)->exists()){
return $this->response->error('could_not_create_trip_errore_ztl', 500);
}
$request->request->add(['user_id' => $user_id]);
$trip = new Trip($request->all());
//$trip->user()->associate($request->user_id);
//$trip->vehicle()->associate($request->vehicle_id);
//$trip->ztl()->associate($request->ztl_id);
if(true)
{
if($trip->save()){
return $this->response->created();
}else return $this->response->error('could_not_create_trip', 500);
}else return $this->response->error('could_not_create_trip_current_user_Error', 500);
}
First question is:
why if comment or uncomment the "associate" method, nothing changes.
Do I need to put these on the controller or I've not weel understand what is the meaning of this method.
Second:
If I send to my controller some data, using form for testing, what is "required" is the 3 foreign keys.
If I send a number that is not on my other "hasmany" table an error is rise, but if try to insert something like "2dsksk" where 2 is a correct ID of the "many" table and then a random string, the ID is taken by the insert as 2, this is correct?
Validation take just the "correct" number part of the data...the question is, why? and this is secure?

associate just sets the foreign key of the child. This means you will need to save your model afterwards.
$trip->user()->associate($request->user_id);
$trip->save();
For the second issue, that's likely MySQL truncating the data based on the data type of the column. If you don't want that to happen, you would likely need to set MySQL to strict mode.
http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sql-mode-strict

Related

Get data on relation 'B' where relation 'A' does not exits in same id in laravel eloquent

I have two tables named "Student" and "Subscription". If there is at least one active plan in the subscription database, I check by date. I need to get the data if no plan is active. Below is the code I used to get the data. But this is wrong because in this query I am getting all the expired data and I should get the data only if there is not even one plan active in the student id.
$expired_student = Student::wherehas('getSubscription', function ($query) use ($current_date){
$query->where('expired_at','<',$current_date);
})->where('status',1)->count();
anyone can please help me to solve this problem
In you Student model, you can define a relationship method called activeSubscriptions, like this:
public function activeSubscriptions() {
return $this->hasMany(Subscription::class)->where(function($query) {
$query->whereNull('expired_at')->orWhere('expired_at', '>', now());
});
}
And you can use this function like this:
$expiredStudents = Student::doesntHave('activeSubscriptions')->get();

How to select multiple row values coma separated in laravel

I am trying to get all the ids with coma separated while doing eloquent relationship.
So here is my current queries
Divrank::where('division_id', 591)->with('meta')->orderBy('position', 'asc')->get()
Divrank table has a one to many relation with Divrankmeta model. So with meta I am trying to return
public function meta(){
return $this->hasOne(Divrankmeta::class)->selectRaw('id, match_id,divrank_id, sum(won) as won, sum(loss) as loss, sum(draw) as draw, sum(points) as points, sum(matchePlayed) as matchePlayed, sum(totalSets) as totalSets, sum(totalGames) totalGames')
->groupBy('divrank_id');
}
So far this query works fine..
I get the result like this screenshot
Ok so in my Divrankmeta model, I have a column called winAgainst and it can have some ids and some left null. So with the meta relation I want to retrieve winAgainst ids with coma separated string inside meta object.
For better understanding, here is how Divrankmeta table looks like
How can I do this?
Thank you.
The relation you created is one-to-one not one-to-many. That's why you are getting a meta object of the first matched row instead of an array that contains all related meta records.
I never put the modification codes into the eloquent functions. Those codes seem belongs to somewhere else. From my perspective, using "resources" and modifying the data there is a better idea.
If you chose the do so:
// Divrank.php
public function metas()
{
return $this->hasMany('App\Models\Divrankmeta');
}
// Divrankmeta.php
public function divrank()
{
return $this->belongsTo('App\Models\Divrank');
}
// DivrankController
public function index()
{
return DivrankResource::collection(Divrank::with("metas")->all());
}
Create a resource file.
php artisan make:resource DivrankResource
Now, you can modify your Divrank collection on the resource file before your controller returns it.
public function toArray($request)
{
$metaIds = [];
forEach($this->metas as $meta) {
array_push($metaIds, $meta['id']);
}
$this['metaIds'] = $metaIds;
return parent::toArray($request);
}
I'm not able to test this code. But it will probably work. If you don't want to use resources, you can create the same functionality in your controller as well. Bu we like to make controllers as short as possible.
Ok I think I solved it, These are the changes I did. Thanks
return $this->hasOne(Divrankmeta::class)
// ->selectRaw('id, match_id,divrank_id, sum(won) as won, sum(loss) as loss, sum(draw) as draw, sum(points) as points, sum(matchePlayed) as matchePlayed,
// sum(totalSets) as totalSets, sum(totalGames) totalGames')
->select(\DB::raw("id, match_id,divrank_id, sum(won) as won, sum(loss) as loss, sum(draw) as draw, sum(points) as points, sum(matchePlayed) as matchePlayed,
sum(totalSets) as totalSets, sum(totalGames) totalGames, GROUP_CONCAT(winAgainst) as winAgainst"))->groupBy('divrank_id');

How to query from database when I have different foreign keys?

I am trying to query data from my database and pass the results to a view called events, the problem I have is that one of my queries will always return the same result because in the where condition the $events_id is the same always. Is there a better way to do the querying? A better logic?
This code is from my controller called EventController:
public function index()
{
$firm_id = DB::table('firms')->where('user_id', auth()->id())->value('id');
$events_id = DB::table('events')->where('firm_id', $firm_id)->value('id');
$events = DB::table('events')->where('firm_id', $firm_id)->get()->toArray();
$actual_events = DB::table('actual_events')->where('event_id', $events_id)->get()->toArray();
return view('events',['events' => $events,'actual_events' => $actual_events]);
}
Since the $events_id is the same every time, the $actual_events will only contain the first result.
The image I have uploaded shows the problem, my table's first three columns are fine. Starting from the fourth they contain repeated values:
As I guess, you need something like this:
$event_ids = DB::table('events')->where('firm_id', $firm_id)->pluck('id');
$actual_events = DB::table('actual_events')->whereIn('event_id', $event_ids)->get()->toArray();
or write about your problem in details and I will try to help you.
you just said that your tables have relation together.
in this case it's better you using the eloquent for that,
first you should type the relations in model of each table like this:
class User extends Authenticatable{
public function cities()
{
return $this->hasmany('App\City'); //you should type your relation
}
}
for relations you can use this link: laravel relationships
after that when you compact the $user variable to your view, you can use this syntax for getting the city value relation to this user: $user->cities;.

Attaching new relation and returning the model

I have a User that has many Positions. I want to update the User (the model and the relation Position), and then return the updated result.
The input will be an array of the format
{
first_name,
last_name,
email,
... (other user information),
positions : [
{
id,
name,
descriton
},
...
]
}
My update function currently is
public function update($id)
{
// This is a validation that works fine
if ( ! User::isValid(Input::all())) return $this->withValidation(User::$errors);
$user = User::with('positions')->find($id);
$new_ids = array_pluck(Input::get('positions'), 'id');
$user->positions()->sync($new_ids);
$user->update(Input::all());
return $user;
}
My User and its permissions are updated, but I still get the old $user's relationship back (i.e. the basic information is updated, and the new positions are updated in the DB, but the returned result is the NEW basic information with the OLD positions).
Right now to fix this, I recall the User::with('positions')->find($id) at the end and return that. But why isn't my code above working?
Correct, sync doesn't update related collection on the parent model.
However you should use $user->load('positions') to reload the relation, it will call only 1 query, without fetching the user again.
Also, you can call load on the Collection:
$user->positions->load('anotherRelation');
because here positions is a Collection, which have load method to lazy load all the related models for each item in the collection.
This would not work, since positions() returns relation object, not collection:
$user->positions()->load('anotherRelation');

Laravel Has One Relation changing the identifier value

I'm not sure this is a real relation. I will try to explain the best way I can.
So first of all, I have three models :
Appartement,
AppartementPrice
The AppartementPrice depends on :
- appartement_id
I would like the AppartementPrice to be retrieve like that :
If there is a specific price for the appartement, then retrieve it, If not retrieve the price for all appartement which is stored in the database with an appartement_id = 0.
So basically what I would like is to do something like that :
public function price()
{
if(isset($this->hasOne('AppartementPrice')->price) // Check that relation exists
return $this->hasOne('AppartementPrice');
else
return $this->hasOne('AppartementPrice')->where('appartement_id', '0');
}
But this is not working.
It does not retrive me the default price.
I guess anyway this is not a best practice ?
I first tried to get the informations like that :
//Check if appartment has a specific price or retrieve default
if($priceAppartement = AppartementPrice::getPriceByCompanyAppartement($this->id))
return $priceAppartement;
else
return AppartementPrice::getDefaultPrice();
But I had this error :
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
when doing :
echo $app->price->price;
How can I check that a relation exists ? And is there a way to do as I describe ?
Thank you
You can't replace relation like this, as what you intend is not logical - you want to retrieve relation that doesn't exist.
Instead you can do this:
public function getPriceAttribute()
{
return ($this->priceRelation) ?: $this->priceDefault();
}
public function priceDefault()
{
// edit: let's cache this one so you don't call the query everytime
// you want the price
return AppartmentPrice::remember(5)->find(0);
}
public function priceRelation()
{
return $this->hasOne('AppartementPrice');
}
Then you achieve what you wanted:
$app->price; // returns AppartmentPrice object related or default one
HOWEVER mind that you won't be able to work on the relation like normally:
$price = new AppartmentPrice([...]);
$app->price()->save($price); // will not work, instead use:
$app->priceRelation()->save($price);
First of all something really important in Laravel 4.
When you do not use parentheses when querying relationship it means you want to retreive a Collention of your Model.
You have to use parentheses if you want to continue your query.
Ex:
// for getting prices collection (if not hasOne). (look like AppartementPrice)
$appartment->price;
// for getting the query which will ask the DB to get all
//price attached to this appartment, and then you can continue querying
$priceQuery = $appartment->price();
// Or you can chain your query
$appartment->price()->where('price', '>', 0)->get() // or first() or count();
Secondly, your question.
//Appartement Model
// This function is needed to keep querying the DB
public function price()
{
return $this->hasOne('AppartementPrice')
}
// This one is for getting the appartment price, like you want to
public function getAppartmentPrice()
{
$price_object = $this->price;
if (!$price_object) // Appartment does not have any price {
return AppartementPrice->where('appartement_id', '=', 0)->get();
}
return $price_object;
}

Resources