Laravel Model recursion supress infinite loop - php

Having the following Laravel recursion in my model how do I avoid accidentally registered relation. What I mean: I have users and users can have many reportees and we want to get back the tree on a given user with the following snippet, which is works fine till the point if user is not a reportee to itself
/**
* User can have many Reporters
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function hasreporters()
{
return $this->belongsToMany('App\User', 'reporting_to', 'acc_receiving_from_id', 'acc_reporting_to_id')
->where('status', 'A');
}
/**
* #return $this
*/
public function children()
{
return $this->hasreporters()->with(['children']);
}
where can I check in the loop if a given id is not equal to the parent id

In function children() you are use relation as query builder. Its not wrong way, but method->with()` search relation from its argument, then call it. Here is recursion :) Try:
public function children()
{
return $this->hasreporters();
}

Related

Laravel - Getting count of nested relationship

I have an application where users can control their properties and leases.
These are the relationships defined:
//Team.php
/**
* A team can have many properties.
*/
public function properties():
{
return $this->hasMany(Property::class);
}
//Property.php
/**
* A property can have many leases.
*/
public function leases():
{
return $this->hasMany(Lease::class);
}
As you can see here, a Team can have many properties, and each property can also have many leases.
I am trying to figure out how I can get the number of leases that is associated with a Team:
$team = Auth::user()->currentTeam;
return $team->properties->leases->count();
However, the above code returns an error:
Property [leases] does not exist on this collection instance.
You could add this method to your Team.php:
public function leasesCount(){
return count(
Team::
join('properties', 'properties.team_id', '=', 'teams.id')
->join('leases', 'leases.property_id', '=', 'properties.id')
->where('teams.id', $this->id)
->get()
);
}
I ended up using a hasManyThrough relationship on the Team model, like so:
//Team.php
/**
* Get all of the leases for the team.
*/
public function leases()
{
return $this->hasManyThrough(Lease::class, Property::class);
}
Then I can simply get the number of leases created by a specific team by:
return $team->leases()->count();

Correct way to set up this Laravel relationship?

I'm after a bit of logic advice. I am creating a system where users login and register their participation at an activity. They can participate at an activity many times. What is the best way to do this? I want to ensure I can use eloquent with this rather than creating my own functions.
I am imagining...
Users:
id
Activitys:
id
name
Participations:
id
user_id
activity_id
time_at_activity
I want to later be able to do such things as:
$user->participations->where('activity_id', 3)
for example.
What is the best way to set this up? I had in mind..
User: hasMany->Participations
Activity: belongsTo->Participation
Participation: hasMany->Activitys & belongsTo->User
Does this look correct?
The users schema can relate to activities through a pivot table called participations:
/**
* Indicate that the model belongs to a user.
*
* #see \App\Model\User
*
* #return BelongsTo
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* Indicate that the model belongs to many activity participations.
*
* #see \App\Model\Activity
*
* #return BelongsTo
*/
public function participations()
{
return $this->belongsToMany(Activity::class, 'participations');
}
$user->participations()->attach($activity);
You may want to add the reciprocal relationships. These can be separated out into traits for code reuse. ->attach(['participated_at' => now()])
You can use Many-to-Many Relationship.
Use Participation as your pivot table. Define relationships as
/* in User */
public function activity()
{
return $this->belongsToMany('App\Models\Activitys','participation','user_id','activity_id')->as('participation')->withPivot('time_at_activity');
}
/* in Activity */
public function user()
{
return $this->belongsToMany('App\Models\Users','participation','activity_id','user_id')->as('participation')->withPivot('time_at_activity');
}
DB schema
// App\User
public function participations()
{
return $this->hasMany('App\Participation');
}
// You may create App\Participation Model
// App\Participation
public function user()
{
return $this->belongsTo('App\User');
}
// Controller
$userParticipations = $user->participations->where('activity_id', 3);
// eager loading version
$userWithParticipations = $user->with(['participations' => function($q) { $q->where('activity_id', 3) }])->get();

Laravel many-to-many query controller

So i have a films table and a conversations table and a pivot table film_conversation
Film (films)
'id'
'filmable_id',
'filmable_type',
Conversation (conversations)
'id'
'last_message_id'
FilmConversation (film_conversation)
'film_id'
'conversation_id'
I am wanting to create a GET request to grab all of the conversations that belong to that specific film, I have this query but unsure if I am grabbing it correctly and how would I write whats being returned in the response?
ConversationController:
/**
*
*/
public function conversations()
{
$this->user = Auth::user();
$film = Film::whereHas('conversations', function ($query) {
return $query->where('id');
})->get();
return $film;
}
I have an additional question, should you directly include this query into the request method or split it out into a private method and include it in to increase readability and clutter of the call? what would be the best practice? It's an endpoint I'm exposing for the front end.
first of all, you're not using the authenticated user, second, you're returning a collection of films that has any conversation, the query constraint isn't doing anything and you can just access $film->conversations to get the collection
public function conversations($id)
{
// Get all conversations for a specified film
return Film::find($id)->conversations;
// Get all conversations in all films that have a conversation
$films = Film::whereHas('conversations')->with('conversations')->get();
$conversations = $films->flatMap->conversations;
return $conversations;
}
Hope this helps
/**
* #param Film $film
* #return Collection|Conversations[]
*/
public function conversations(Film $film)
{
return $film->conversations;
}
in route file
Route::get('conversations/{film}');
this code will return json representation of conversations models collection https://laravel.com/docs/5.7/eloquent-serialization#serializing-to-json
or it return 404 if film id not exist.

Laravel 5.3 get belongsToMany and count pivot

I have next models:
class Polling extends Model
{
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function participants()
{
return $this->belongsToMany(Participant::class, 'participant_poll', 'poll_id');
}
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function results()
{
return $this->belongsToMany(Participant::class, 'poll_results', 'poll_id');
}
}
class Participant extends Model
{
public function polls()
{
return $this->belongsToMany(Polling::class);
}
public function results()
{
return $this->belongsToMany(Polling::class);
}
}
poll_results - pivot table have structure: id, poll_id, participant_id.
I need view next table:
№|participant.name|Count vote|
1|Mike |15 |
2|................|10 |
..............................
Count vote get pivot table poll_results.
Help please, write query.
$poll = Polling::first();
$poll->participants()->get();
You may want to use withCount() method.
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models
Your query would look like this one:
Participant::withCount('polls')->get();
This will add new property to results called polls_count

Using AR findAll function giving only one object back when using the with statement

I am having an issue with my Yii install where I am trying to get a fairly basic query back but I am not getting the results back that the online tutorials are saying that I should get. I have 2 models that look roughly like this:
Pricing:
class Pricing extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return Pricing the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'pricing';
}
/**
* #return string the primary key
*/
public function primaryKey(){
return 'ID';
}
...
/**
* #return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'xpricing_routes' => array(self::HAS_MANY, 'PricingRoutes', 'ID_pricing'),
);
}
and PricingRoutes:
class PricingRoutes extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return PricingRoutes the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'pricing_routes';
}
/**
* #return string the primary key
*/
public function primaryKey(){
return 'ID';
}
...
/**
* #return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'xpricing' => array(self::BELONGS_TO, 'Pricing', 'ID_pricing'),
);
}
Then in the controller we have:
$criteria = new CDbCriteria;
$criteria->with = array('xpricing_routes');
$criteria->together=true;
$pricing_records = Pricing::model()->findAll($criteria);
$pricing_records_arr = CHtml::listData($pricing_records, 'id', 'name');
echo '<pre>';
print_r($pricing_records);
print_r($pricing_record_arr);
echo '</pre>';
As you probably already know, we have 2 tables called pricing and pricing_routes. The pricing routes table has a foreign key called ID_pricing that goes to the ID field in the pricing table. The pricing table has one entry and the pricing_routes table has 4 entries that all have the primary key for the one item in the pricing table in the ID_pricing field. So we should be getting 4 results to the query that we are running and when I run the query that Yii is generating with AR, that is what I get.
The problem that we are having is that the $pricing_records variable is an array that only has one Pricing object. That object contains the data we need but not really in a usable fashion. The $pricing_records_arr variable is just an empty array. The documentation that I have found seems to suggest that we should be getting an array of pricing objects each containing the information from the pricing_routes table as well. We are aware that using AR may not be the best way to get this data but we have our reasons for getting this to work so any ideas on how to do that would be much appreciated.
EDIT:
It turns out that this ended up being a misunderstanding of what I was getting back. The comments on this question gave me the information that I needed.
If you call
$pricing_records = Pricing::model()->findAll($criteria);
you'll get only one active record with properties filled with the values from your table "pricing".
If you want to get all the records from "pricing_routes" belonging to this specific "pricing" you have to call
$pricing_records->xpricing_routes
where "xpricing_routes" is the name of the relationship you have correctly defined in your model. It returns array of PricingRoutes or null if there is no matching record.
if you use findall it will return an array even there is one record
$pricing_records = Pricing::model()->findAll($criteria);
foreach($pricing_records as $var){
$var->xpricing_routes->ID_pricing;//any variable
}
or
if there only one field you can use
$pricing_records = Pricing::model()->find($criteria);
$pricing_records->xpricing_routes->ID_pricing;//any variable

Categories