Count views with Session - laravel

I'm new to laravel. I found a way here how to count article views, I used it on my own and it works as it should
$viewed = Session::get('viewed_article', []);
if (!in_array($article->id, $viewed)) {
$article->increment('views');
Session::push('viewed_article', $article->id);
}
But the only thing I do not fully understand is how it works and what it does, which makes me feel a little uneasy.
Who is not difficult, can you explain how this function works?

The first line:
$viewed = Session::get('viewed_article', []);
uses the Session facade to get the data with the key viewed_article from the session, or if nothing exists for that key, set $viewed to an empty array instead (the second argument sets the default value).
The next line, the if statement:
if (!in_array($article->id, $viewed)) {
makes sure that the current article id is not in the $viewed array.
If this condition is true (i.e. the article is not in the array), then the views are incremented (i.e. increased by one) on the article:
$article->increment('views');
Lastly, the article id is added into the viewed_article session data, so the next time the code runs, it won't count the view again:
Session::push('viewed_article', $article->id);

Related

Why does my forget() method not remove object from collection?

I have a collection of "Tickets", using the random collection utility method I select one from the list. The "Tickets" collection should now remove (or forget) that randomly selected ticket so I can further process that collection. Using the forget method doesn't appear to do what is described in the documentation or (more likely I'm missing something).
Can someone spot whats wrong in my code?
$tickets = Tickets::all();
$total_winners = 5;
$selected_tickets = $tickets->random($total_winners);
$jackpot_winner = $selected_tickets->random();
$selected_tickets->forget($jackpot_winner->id); // this line should remove the $jackpot_winner
When I print the contents of $selected_tickets on lines 3 and lines 5, they have the exact same items, including the $jackpot_winner.
Forget function uses the collection key not the id from the model. To achieve what you want you may use this method:
$selected_tickets = $selected_tickets->except($jackpot_winner->id);
https://laravel.com/docs/8.x/collections#method-except

Angular array filter is not working on a list of string

I have an array of string, and want to filter out a particular string after some operation. But, it seems I am doing something wrong there.
this.displayUser.followers.filter(userId=>userId !== this.loggedUser.userid);
Here, followers is an array of string -> string[] and upon some action (say, unfollow); I want to remove the logged user's id from the displayed user's followers list.
However, this filter operation does not seem to work.
On the other hand I tried using splice which is working perfectly fine.
this.displayUser.followers.splice(
this.displayUser.followers.findIndex(userId=>userId === this.loggedUser.userid)
,1);
I am unable to understand what am I doing wrong in the first approach?
Array.filter does not change the array it performs its action on, but returns a new array with values that passed the condition.
In order to use .filter and have the result saved, you can do:
this.displayUser.followers = this.displayUser.followers.filter((userId) => userId !== this.loggedUser.userid);
This will remove all entries where userId === loggedUser.userid.
.splice on the other hand manipulates the array it performs its actions on, hence you will immediately see the results as expected.

Testing oneToMany relationship Laravel, Eloquent doesn't work

I can't get my head around this:
$fragment = factory(Fragment::class)->create();
$this->assertCount(0, $fragment->values);
fragment->fetch(); // updates the 'values' by adding one Value object.
var_dump($fragment->id); // i.e. 6
var_dump(Fragment::first()->id); // 6
var_dump($fragment->values->count()); // 0
var_dump(Fragment::first()->values->count()); // 1
$this->assertCount(1, $fragment->values);
I use DatabaseTranscations, so after a Fragment is created, there is always one and only one. Thus, $fragment and Fragment::first() are the exact same instance. Yet... the values relationship is different. How can this be the case?
Note that this happens only during testing, when I manually test this through my controller (and the values are passed to the blade template page) it works just fine. I am confused :S.
Any ideas?
Relationship attributes ($fragment->values) are only loaded once. They are not kept up to date when you add or delete items from the relationship. They do not hit the database every time to check for changes.
Your second line is $this->assertCount(0, $fragment->values);. Accessing $fragment->values here lazy loads the relationship, and as your assert proves, it is empty.
You then call $fragment->fetch(), in which your comment says it adds a Value object to the fragment. However, your relationship attribute ($fragment->values) has already been loaded from the previous statement, so it will not reflect the additional Value object you added to the relationship.
Therefore, even after the call to fetch(), $fragment->values is still going to be an empty collection. Fragment::first()->values will contain the newly related Value though, because it is getting a new instance of the Fragment, and when it loads the values for the first time, it will pick up the related Value.
When you need to reload the relationship, you can use the load() method. If you add this after your call to fetch() (or put it in your fetch() method, whichever makes sense for you), your test will work fine.
$fragment = factory(Fragment::class)->create();
$this->assertCount(0, $fragment->values);
$fragment->fetch(); // updates the 'values' by adding one Value object.
var_dump($fragment->id); // i.e. 6
var_dump(Fragment::first()->id); // 6
var_dump($fragment->values->count()); // 0
// reload the values relationship
$fragment->load('values');
var_dump($fragment->values->count()); // 1
var_dump(Fragment::first()->values->count()); // 1
$this->assertCount(1, $fragment->values);
The other option you have is to use the relationship query by accessing the relationship method instead of the relationship attribute. If you do $fragment->values()->count() (note: values(), not values), that will hit the database every time and always return the current count.

Session variable on refresh

I have laravel controller like this:
public function postSessionTopic() {
$article_id = Input::get('article_id', 0);
$comment_id = Input::get('comment_id', 0);
\Session::set('page_topic_id', $article_id);
\Session::set('page_comment_id', $comment_id);
\\comment - I have tried \Session::put too, but that doesn't change anything
}
I use it, when user click on a article. I print_r out my session variable in this controller and everything looks fine. But after that I refresh my page, and there I read value from session, and sometimes it load old value or doesn't load anything. I can't understand why, because in controller i can see, that correct value is saved!
In my page, i get that value like this:
\Session::get('page_topic_id', 0)
Probably you do something wrong. You should make sure that in both cases you uses exactly same domain (with or without www).
In this controller when you don't have any input you set to session variables 0. This can also be an issue if you launch this method when you don't have any input.
You could try with adding this basic route:
Route::get('/session', function() {
$page_topic = Session::get('page_topic_id', 1);
$page_comment = Session::get('page_comment_id', 1);
echo $page_topic.' '.$page_comment.'<br />';
$article_id = $page_topic * 2;
$comment_id = $page_comment * 3;
Session::set('page_topic_id', $article_id);
Session::set('page_comment_id', $comment_id);
});
As you see it's working perfectly (but you need to remove session cookie before trying with this path).
You get
1 1
2 3
4 9
8 27
and so on. Everything as expected
Answer was - two ajax at one time. Don't do that, if you store something in session.
The session in Laravel doesn't consider changes permanent unless you generate a response (and that's the result of using symphony as it's base). So make sure your app->run() ends properly and returns a response before refreshing. Your problem is mostly caused by a die() method somewhere along your code or an unexpected exit of PHP instance/worker.
This is probably not your issue but if you are storing your laravel session in the database their is a limit on how large that value can be. The Laravel session migration has a field called "payload" that is a text type. If you exceed the limit on that field the entire session gets killed off. This was happening to me as I was dynamically adding json model data to my session.
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->unique();
$table->text('payload');
$table->integer('last_activity');
});
How much UTF-8 text fits in a MySQL "Text" field?

Model records ordering in Spine.js

As I can see in the Spine.js sources the Model.each() function returns Model's records in the order of their IDs. This is completely unreliable in scenarios where ordering is important: long person list etc.
Can you suggest a way to keep original records ordering (in the same order as they've arrived via refresh() or similar functions) ?
P.S.
Things are even worse because by default Spine.js internally uses new GUIDs as IDs. So records order is completely random which unacceptable.
EDIT:
Seems that in last commit https://github.com/maccman/spine/commit/116b722dd8ea9912b9906db6b70da7948c16948a
they made it possible, but I have not tested it myself because I switched from Spine to Knockout.
Bumped into the same problem learning spine.js. I'm using pure JS, so i was neglecting the the contact example http://spinejs.com/docs/example_contacts which helped out on this one. As a matter of fact, you can't really keep the ordering from the server this way, but you can do your own ordering with javascript.
Notice that i'm using the Element Pattern here. (http://spinejs.com/docs/controller_patterns)
First you set the function which is gonna do the sorting inside the model:
/*Extending the Student Model*/
Student.extend({
nameSort: function(a,b) {
if ((a.name || a.email) > (b.name || b.email))
return 1;
else
return -1
}
});
Then, in the students controller you set the elements using the sort:
/*Controller that manages the students*/
var Students = Spine.Controller.sub({
/*code ommited for simplicity*/
addOne: function(student){
var item = new StudentItem({item: student});
this.append(item.render());
},
addAll: function(){
var sortedByName = Student.all().sort(Student.nameSort);
var _self = this;
$.each(sortedByName, function(){_self.addOne(this)});
},
});
And that's it.

Resources