Description:
I have a "logout" mechanism in my project. Basically, it creates a record into a DB table and I check if the logged_out_at has a value.
Now, to make sure this mechanism is proper, I've implemented it into a custom middleware that gets called whenever the api gets called.
[1] $record = Logout::where("user_id", Auth::id())->where("logged_out_at", null)->first()
When the logout record exists, I'd call ->update and the set a value for logged_out_at. Then, redirect the user to a logout route or issue a 401 Not authorized response.
[2] Logout::where("user_id", Auth::id())->where("logged_out_at", null)->update($params);
Problem:
Imagine the user clicking "refresh" or opening multiple microservices that request the api multiple times at the same time.
[1] will be called, [2] will be executed. In the second middleware call, the [1] will be called, the [2] of previous could be in execution process, therefore, I'd get a [1] valid response, which shouldn't be!
Solution
I've tried using Redis cache, use Auth::id() as key. If the cache exists, I return and don't search for anything. Nevertheless, I've faced the same problem. Redis would still take time to execute, save and retrieve the pair.
I've tried using a global variable (array with Auth::id() is key), but it would be a mess if I have over 1K users.
I believe my way of verifying the logout is wrong, but I couldn't find any helpful resources for this.
Since your needs are that an event (notification), that is triggered when you "logout", needs to trigger only once then you can make them tightly dependent via the result of the method update()
update() returns the number of rows affected by the query and since the query is conditioned on logged_out_at being null then:
$loggedOut = Logout::where("user_id", Auth::id())->where("logged_out_at", null)->update($params);
if ($loggedOut) {
sendNotification();
}
Related
I’ve read that you should not use GET requests if you are modifying the database. How would you record analytics about your website then?
For example, I want to record page views whenever someone visits a page. I would need to update views = views + 1 in the database. Is this OK, despite using a GET request, or is there another technique? Surely, not every request should be a POST request.
The general advice about how to use POST vs. GET shows up in RFC 1945 from 23 years ago:
The GET method means retrieve whatever information (in the form of an entity) is identified by the Request-URI.
POST is designed to allow a uniform method to cover the following functions:
Annotation of existing resources;
Posting a message to a bulletin board, newsgroup, mailing list, or similar group of articles;
Providing a block of data, such as the result of submitting a form [3], to a data-handling process;
Extending a database through an append operation.
These guidelines remain in effect to this day, but they cover the primary purpose of the user's page request.
The act of incrementing a view counter is incidental to the primary purpose of the request, which is to view the page content. Indeed, the user is likely unaware that this database update is occurring.
(Of course, you must expect that you will receive duplicate requests as users move through browser history, caches are populated, or spiders crawl your pages. This wouldn't be the case if a POST request was made.)
It's ok.
When you make POST request, you actually wait for POST params to come and you build your database insert query based on parameters which you've got from browser.
On GET request you actually implement your own business logic, so user won't ever know what is going on the side.
And for the finish, actually sometimes you can do something, what's going against rules, rules are good, but we are able not to follow them, that's what makes us human, if we would strictly follow all the rules, it would be cumbersome.
I am deleting a "mob" then redirecting to the index page. My problem is that if I use $this -> dispatcher -> forward() when I get to the index page (which displays all mobs) the deleted mob will still display due to forward()'s behavior of not refreshing the page.
Usually I solve this problem by using response-> redirect(), however I cannot use it here as I use dispatcher to send params like this.
return $this -> dispatcher -> forward(array('controller' => 'mob', 'action' => 'index', "params" =>array("alert" => "Mob deleted.")));
My question is, what is the best practice to send my parameters but also refresh the page so deleted objects aren't rendered after dispatching?
I get to the index page (which displays all mobs) the deleted mob will
still display due to forward()'s behavior of not refreshing the page.
That is not entirely true and this has to do with caching database calls during the request or you simply not refreshing the displayed data. I'd say more if you provided the code for both actions, but this shouldn't be hard to figure out on your own. Your index action must load the model set every time its called, so if you have deleted a model in the forwarding action, there should be no reason for that model to be present in the consecutive load in the forwarded action.
Generally forwarding would be better technique than reloading the page – you don't make another request to the server for no real reason. If you need to use redirection there's a number of ways you can pass alerts between the pages, e.g., storing the alert queue in the session or database. Phalcon has the Flash component for displaying flashing messages, which allows to use the session approach.
How to avoid caching in the socket?
I've executed a script listening for sockets, so there I check if the user is logged or not:
Auth::check();
i've tested it, but if I logout or log in ,the status doesn't changes, also this happens with the database eloquent queries, the fluent works fine, any ideas on how to fix this problem?
I need to restart the server to update the session in the sockets, that restart
also I've tried to use raw $_SESSION, it also caches, but I need to check the fresh version of it in the sockets...how to do this?, spent hours but still can't figure it out
I think you have to overwrite the user() Method inside the Guard class. The method originally fetches the user only once per request and you have to disable that for your usecase. See here from Guard.php
// If we have already retrieved the user for the current request we can just
// return it back immediately. We do not want to pull the user data every
// request into the method becaue that would tremendously slow the app.
if ( ! is_null($this->user))
{
return $this->user;
}
It should be simple:
Hook a MODEL_save_after event (or MODEL_save_before if that’s more appropriate).
Check getData() vs getOrigData() to see what changes the user has made.
In the customer_address model, edited through the backend, both save events are triggered twice. The first time customer_address_save_before is triggered, followed by customer_address_save_after.
In both cases getOrigData() and getData() are identical, except getData() has a new updated_at value, and has a store_id set (is this a bug?). So, the model doesn’t have the submitted data from the user yet. The events are both before entering user data or validation, so this is of no use.
customer_address_save_before is triggered, followed by customer_address_save_after a second time. This time (in both cases), getOrigData() is empty, and getData() now has all the submitted data from the user. So I can’t compare these events either! It appears this is after validation, saving, the lot!
Why the save process appears to occur twice? Magento v1.3.2.4.
I wound up hooking customer_address_save_before, and comparing the results to what was in the database like so:
<?php
customer_address_save_before_listener ($event)
{
$address = $event->getCustomerAddress();
$database_address = Mage::getModel('customer/address')->load($address->getId());
}
?>
And comparing the getData() returns from the two. There were three gotcha's that I came across:
Use getEntityTypeId() on $address and check it. Despite hooking 'customer_address_save_before', you also get OrderAddress models being sent to your listener (this seems wrong to me, but ah well).
Check for arrays in $address->getData() values. For example, 'street' is returned from the DB as a single string, while the address your listener is passed has this exploded on endlines.
The CustomerAddress your listener is passed has a 'store_id'. Even though CustomerAddress doesn't store 'store_id', and it doesn't get saved (or loaded from) the database.
I have a list of "online users", which I refresh every 30 seconds with Ajax.PeriodicalUpdater from prototype.js.
There is an issue, that if a user has two tabs/windows open with the site, logs out in one of them, the PeriodicalUpdater is not canceled.
This means that PeriodicalUpdater updates my block element with the entire login page, as I have a restful authentication, that redirects to that.
I am using PHP sessions, and I really cannot get my head straight on this one.
Can any of you guys point me in the right direction?
I would consider changing the method that returns the results so that it doesn't require an authenticated session to access it, but it returns valid information only when there is an authenticated session. Otherwise, it returns a value indicating that the updates should cease and a suitable message for display in your online user's block. This would mean that you'd probably need to return JSON instead -- not a bad thing -- and either combine it with an HTML snippet as part of the JSON or simply construct the HTML on the client from the JSON data (better IMO since the view is the correct place to do mark up).
When creating the PE, keep a reference to it:
// At global scope, or ideally if you have a namespaced object, use that
var thePE;
// Where you create the PE
thePE = new PeriodicalExecuter(yourFunction, 3);
And when you want it to stop, tell it to stop (assuming it has been started):
if (thePE) {
thePE.stop();
thePE = undefined;
}
(PeriodicalExecuter#stop docs here.)