I am creating a system of newsfeed, and as you can easily guess, it is beyond my skills. Please be kind to put me on the right track or provide something I can go on with.
I have several hundred events (model name is Event1, table 'events') I also have a pivot table in which users can assign any event's importance (values 0,1,2,3)
The relevant columns of the pivot table user_attitudes (Model Userattitude) are
id
, item_type
, item_id
, importance
, attitude
, creator_id
An example three record are:
456 - event - 678 - 2 - 4
457 - event - 690 - 3 - 15
458 - event - 690 - 1 - 4
459 - participant - 45 - 1 - 4
Plain English: Total aggregated importance of the event #690 is '4', while the event #678 is '2'. Therefore in my ranking the event #690 should be listed as first.
Just to see the bigger pic: the user #4 also rated participant # 45 as importance = 1.
The table services many models - the above example include two - just to give a better image of what I have.
WHAT I NEED:
I wish to print a ranking of top 5 events (and later other models). I wish to be able to use two methods of calculating the total score:
- by counting the actual value (0,1,2,3)
- by counting any value above 0 as 1 point.
I want to generate views which filter events by this criteria:
- at least one user set the importance to '0' (I need it to flag an event as untrustworthy)
- events which has not been rated yet
- reverse of the above - events which are rated by at least one user
- events listed by number of users who assigned any importance to it
This is easy, but still I have no idea how to make it happen. The same filters as the above #2, but related to a particular user decisions:
- list 5 or 10 events (random or newest) which has not yet been rated by the user maybe something like this would be an answer:
$q->where('creator_id', '=', Auth::user()->id);
Relevant code: As I don't really grasp the merged relations, I might fail to show everything needed to provide help - ask for more code in comments.
Models:
Event1 (table 'events'):
public function importances()
{
return $this->morphMany('Userattitude', 'item');
}
public function user_importance($user)
{
return $this->morphMany('Userattitude', 'item')->where('creator_id', ($user ? $user->id : NULL))->first();
}
User: (table 'users' - standard user table)
public function importances()
{
return $this->hasMany('Userattitude', 'creator_id');
}
In model Userattitude (different from User, table name 'user_attitudes')
public function events()
{
return $this->morphTo('item')->where('item_type', 'event');
}
public function event()
{
return $this->belongsTo ('Event1', 'item_id');
}
PROBLEMS IN REPLY TO @lucas answer:
PROBLEM 1.
table name 'items' keeps me confused as in my project 'items' are events (model Event1), the participants (model Entity) and other objects. Can we stick to my naming until I get hold of the knowledge you are providing? it also contains column named attitudes, which is used for blacklisting particular items. For instance, an item of type 'entity' (possible participant of multiple events) can be voted by user two-wise: - by importance set by an user (we are doing this now, values available to use are 0,1,2,3) - by attitude of an user toward (possible value (-1, 0, 1) Such solution allows me to compute karma of each item. For instance -1 x 3 = -3 (worst possible karma value), while 1 x 2 = 2 (medium positive karma).
In consequence I am unable to use queries with the users method. It is still too confusing to me, sorry. We diverted too far from my original mental image. Consider this query:
$events = Event1::has('users', '<', 1)->get();
If in Event1 I declare
public function users()
{
return $this->morphToMany('User', 'item', null, null, 'creator_id');
}
Note: User is the standard users table, where username, password and email are stored
I get this error:
[2014-12-28 05:02:48] production.ERROR: FATAL DATABASE ERROR: 500 = SQLSTATE[42S02]: Base table or view not found: 1146 Table 'niepoz_niepozwalam.items' doesn't exist (SQL: select * from `Events` where (select count(*) from `users` inner join `items` on `users`.`id` = `items`.`creator_id` where `items`.`item_id` = `Events`.`id` and `items`.`item_type` = Event1) >= 1) [] []
if I change the method definition to
public function users()
{
return $this->morphToMany('Userattitude', 'item', null, null, 'creator_id');
}
Note: Userattitude is model (table name is 'user_attitudes') where i store user judgments. This table contains columns 'importance' and 'attitude'.
I get the same error.
If I change the method to
public function users()
{
return $this->morphToMany('User', 'Userattitudes', null, null, 'creator_id');
}
I get this:
[2014-12-28 05:08:28] production.ERROR: FATAL DATABASE ERROR: 500 = SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user_attitudes.Userattitudes_id' in 'where clause' (SQL: select * from Events
where (select count(*) from users
inner join user_attitudes
on users
.id
= user_attitudes
.creator_id
where user_attitudes
.Userattitudes_id
= Events
.id
and user_attitudes
.Userattitudes_type
= Event1) >= 1) [] []
Possible solution: the 'user_attitudes' table alias with name 'items'. I could create a view with the required name. I did it, but now the query produces no results.
PROBLEM 2
should I rename creator_id into user_id - or keep both columns and keep duplicated information in them? The creator_id follows conventions and I use it to create records... how to resolve this dillema?
PROBLEM 3.
As far as I understand, if I want to get a USER-RELATED list of top-5 events, I need to ad another line to the code, which narrows search scope to records created by a particular logged in user:
Auth::user()->id)
The code would look like this: All with importance 0
$events = Event1::whereHas('users', function($q){
$q->where('importance', 0);
$q->where('creator_id', '=', Auth::user()->id);
})->get();
right?
PROBLEM 5:
Ok, I am now able to output a query like these:
$rank_entities = Entity::leftJoin('user_attitudes', function($q){
$q->on('entity_id', '=', 'entities.id');
$q->where('item_type', '=', 'entity');
})
->selectRaw('entities.*, SUM(user_attitudes.importance) AS importance')
->groupBy('entities.id')
->orderBy('importance', 'desc')
->take(6)
->get();
and in the foreach loop I can display the total importance count with this code:
{{$e->importance or '-'}}
But How I could display count of an alternative query: SUM of values from another column, named attitude, which can be computed in this SEPARATE query:
In other words, in my @foreach loop I need to display both $e->importance and a computed SUM(user_attitudes.attitude) AS karma, which for now can be received with this query:
$rank_entities = Entity::leftJoin('userattitudes', function($q){
$q->on('entity_id', '=', 'entities.id');
$q->where('item_type', '=', 'entity');
})
->selectRaw('entities.*, SUM(userattitudes.karma) AS karma')
->groupBy('entities.id')
->orderBy('karma', 'desc')
->take(5)
->get();
My solution would be to create some extra columns in the 'entities' table: - karma_negative - karma_positive to store/update total amount of votes each time someone is voting.