Why are symfony flash messages not removed from session? - php

I wrote a controller in Shopware 6 (symfony based) that adds a flash messages via $this->addFlash(...).
As expected the message is shown in the storefront (product detail page).
In the function \Symfony\Component\HttpFoundation\Session\Flash\FlashBag::all the message is removed as expected (checked via xdebug).
But when I refresh, the flash message is shown again and is also contained in the session.
I also checked this directly in the PHP session:
$_SESSION['_symfony_flashes']
The message is correctly removed there, but reappears on the next page load.
The only idea I have is, that the session is not persisted after the flash message is removed from it. But I never faced such behavior in the Symfony sessions or PHP sessions.
What could be the reason for this?

My best guess is that the page is cached with the flash message intact. Afaik flash messages are primarily used on routes that are exempt from caching. The product detail page is not one of those by default. You might have to enrich the cache key for the page by a parameter denoting whether the flash message should be shown or not.

Adding to dneustadt's answer: As the product detail page is cached, also your flash message will not show if the detail page is generated and cached without the addFlash() and later your condition for the addFlash() becomes true: Then your controller will just not be hit and the cached page without the flash message will be shown.

Related

Shopware 6 Saving Affiliate/Campaign code to session at anytime I enter the shop

I'm on a Production System 6.4.2.1, but had the same problem on a newer version 6.4.14
If you enter the shop for the first time with a query parameter URL for example https://shop/?affiliateCode=test&campaignCode=test, the codes will not be saved to the session to use it for example in the cart or have this flags on an order (which is standard shopware function).
After you entered the shop you have to navigate to another page than paste in the url with query parameter to get it saved to the session.
If you than delete your site data and enter the shop again with this
query parameter url its not working again.
This issue happens only in production if cache is turned on.
As far as I could investigate this issue I noticed that for the very first time symfony fires the "BeforeSendResponseEvent" which Shopware listens to but this just terminates the first request with our query parameters
So now if you navigate to another page and enter the url with query parameter again, than Symfony will trigger the KernelEvent which Shopware listens to to add the query parameters to the session.
Did anyone else had trouble with this issue before?
Yeah, I think you got it right. Looking at the listener the corresponding event isn't dispatched if the http cache is hit. The affiliate and campaign parameters become part of the cache key and therefore consecutive requests will result in cache hits, avoiding the listener.
I think your best bet might be to create a ticket on the issue tracker. Ultimately this will need to be fixed in the codebase.
For now the only way to be sure the codes are stored in the sessions would be to publicize URLs with the parameters on routes that aren't http cached, like /account/register. For workarounds you could register your own controller that avoids the http cache and redirects to the home page, just for the sake of not missing these parameters. Another option would be to listen to to HttpCacheHitEvent as described here and set the codes to the session yourself, even though you might also have to start the session at that point.

Custom extension is not passing magento 2 validation

We have created a simple Magento 2 extension and verified it using their tool: https://github.com/magento/marketplace-eqp
However, when we submit the extension for technical review, it always fails with the following error:
Magento extension review error
I have searched all over and all I found was to make sure that we did not have the attribute cacheable="false" in any block that we were injecting because it would invalidate the entire full page cache. We do not have that attribute at all.
Is there anything else I should test in order to pass Magento 2 technical review?
Thank you!
You should check that pages in report
Assertions:
AssertHitHeader: validates that after sending a request for the test page, the server returns HIT for the expected header.
So
Inspect page headers-
Success criteria:
The first time accessing the page will always be a MISS.
Subsequent times accessing the page will be a HIT.
How to verify - http://devdocs.magento.com/guides/v2.0/config-guide/varnish/config-varnish-final.html

Detecting page reload after clicking back button in PHP

I am looking for a way to detect when a page is reloaded after clicking the back button, so I can selectively ignore errors. Let me explain why:
Imagine a page that displays some data, identified by an id:
/show/some/data?id=5
Initially, the id exists and the page is displayed. If the id does not exist, an error message is shown and an error is logged, because that should not happen and would indicate a broken link in the application.
Now imagine the user looks at the data, decides to delete it, and after deleting, uses the back button to go to the same page again (BTW this is not a hypothetical, I have seen this in my application). Now, the id is no longer valid, triggering an error. If I could distinguish between the initial page load and the second page load after using the back button, I could be more lenient in my error handling. My reasoning being that a broken (forward) link in the application is a fatal error. A broken link after clicking back (when there was none initially) is very likely caused by some action the user took in the meantime. In that case I would much rather redirect the user to an overview page than show an application error.
I believe one way to solve this would be to attach some randomly generated id to the url:
/show/some/data?id=5&rnd=<?php print rand(); ?>
and log the random ids that have been used in the session. If an id repeats itself, I can assume that the page has been reloaded, and selectively ignore some errors.
However, that would require altering many links in the application. I could also use javascript/jQuery to alter all links on the page to the same effect:
$("a").attr('href', function (i, h) {
return h + (h.indexOf('?') != -1 ? "&" : "?") + "rnd=" + Math.random ();
});
That's slightly less invasive, but still rather heavy handed for solving such a seemingly trivial problem. I wonder if there is or can be a self-contained way to do this. Is there any way for the backend application to distinguish if a page is loaded by forward clicking on a link or reloaded after clicking back? Or is there a more elegant solution with javascript?
There's no perfect solution for this since you're trying to (sort of) change a browser's behaviour. The simplest idea I can think of is setting a session variable with a list of deleted pages, and pushing the page IDs into it on the delete page.
Then, you need to update your error handler to additionally check for the presence of the requested page ID in the deleted pages list. That way you won't have to mess with URLs at all.
Here's an example flow:
user requests page id 1
app checks the db, it doesn't exist
app checks the session, it's not in the deleted pages list
error message shown, error logged on the server
user requests page id 2
app checks the db, it exists, show the page to the user
user clicks the delete button
ID of the page is added to the session list of deleted page and the page is deleted
user goes back (or types the url manually, this is a bonus feature)
app checks the db, id 2 doesn't exist
app checks the session, id 2 IS in the deleted pages list
error message shown, no errors logged
You can also take this one step further and track all the visited pages, so you'll know that if something was there a few minutes ago, and now it isn't, the user must have deleted it. This would allow you to handle more such events if needed.

GET an POST data for Mozilla

I am doing my work in PHP.
I have 3 pages,
A is plain HTML and contains a search field.
B is .php and returns results of the search.
C is also php and allows user to update some details for the displayed results.
When I'm doing Refresh my B page or Go-Back from C to then I
get this message
"To display this page, Firefox must
send information that will repeat any
action (such as a search or order
confirmation) that was performed
earlier."
I saw "When i'm using "POST" method then I get this message, if I'm used GET then
I don't.
Any buddy Explain me ,why???
The GET method should be used to obtain information from a web page.
The POST method should be used to send information to a web page.
The reason it asks you to confirm whether or not to send information again is because it's not always the user's intention to repost a form if they press back. One example is at an online store, you would not want to repost a form to purchase a product twice, otherwise you could be billed for the product twice. This is theoretical of course since someone who makes an online store should ensure that an accidental purchase can't happen.
Also, if you use GET, then all information is appended to the URL of the PHP page. This is a potential security issue, especially if the form contents are private. For such forms, you should be using POST.
A wild guess,
POST is not written in the URL, so you need to resend it, while GET, when you click to return to B, the arguments are still in the URL so you dont need to resend.
Mozilla added this message to warn you from sending the information twice.
Like in the form of registration, you don't want to register twice.
Firefox developers added that warning for POST method. It will warn you for POST in case of back/forward also.
This is an added safeguard for users. Because, most shopping carts/banking portals use POST method for checkout/transaction confirmation (actually I have not seen or developed any web app to use get method for this purpose).
So, Firefox (and most other common browsers) warn you in this scenario (when your are sending POST request indirectly, i.e. using back/forward/refresh button). This prevents the user from multiple checkout.
Another reason to add this warning is, sometimes chekout is time consuming. So, when some time is passed after the original submission, some impatient users think that the browser/server has stopped working. So, they tend to press the refresh button. This warning gives them a good hint.
I think the point is that GET requests should be used to get information without changing anything on the server so if you reload the same information there's no issue. POST requests should be used to change data on the server so when you reload the page that may have undesirable effects.
Firefox should normally allow you to navigate back to your B page from your C page. However if your B page is not in the cache, possibly because it sends a Cache-control: no-store header, then you will get the POSTDATA warning.
On the other hand explicitly reloading page B will always generate a POSTDATA warning.
When you submit data in the POST method, it sends headers to the page you submit to. When you refresh the page or go back, your browser repeats your POST request and Firefox warns you of this.

Should I go with AJAX and JQuery's complexity and speed or GET's simplicity?

If a user tries to log in and the login fails the page should display an error message to the user. There are two main ways I see to do this: use a form action on the HTML page and in the php script if the login information is incorrect redirect with header to the login page with a $_GET value like loginfailed. The login page would check for this value and if it exists it would display the error.
The second way I see to do this is not use a form at all and instead use JQuery to capture the submit button press and use AJAX to determine if an error occurs. The php file would echo back a status and the javascript file would interpret it and if it was loginfailed, it would use JQuery to append the error message on to the page.
Now I will go over what I feel the pros and cons of each method are.
Method 1 Pros:
Very simplistic with no need for JQuery, Javascript, and AJAX.
The error status is displayed within the URL as well.
Method 1 Cons:
Since there is a header call, a redirect is necessary. Also, the login page must be reloaded. It is a small page but it is a reload nonetheless.
The status message is displayed in the URL. This means that users can type in status messages in to the URL and receive error messages on the page for errors that did not actually occur. Is this a problem? Maybe. Maybe not.
Method 2 Pros:
Since it is using AJAX, there is no need to load another URL and thus, no extra page is loaded.
This method uses JQuery to update the page with the error message so no redirect is necessary.
The error status is not displayed in the URL.
Method 2 Cons:
Much more complex than the first solution.
An external javascript file is needed and must be loaded every time the login page is accessed regardless of whether or not it is used.
The default behavior of the submit button is overridden and annulled. Its only behavior comes from its interaction with the javascript file.
What would SO do? I would like to stay away from answers such as "it depends on how much traffic your site would have" if that would be at all possible.
Always use the simplest solution possible until/unless there's a very good reason to do otherwise. It's better to finish something that's maybe (and maybe not) less than ideal than to deliver something gold-plated eventually, maybe.
Also, I generally prefer to follow a progressive enhancement strategy, such that everything works without Javascript, and then add Javascript to make it work in an improved manner. This has the added benefit of being functional, even when/where Javascript is disabled.
I think you fail to grasp the matter.
Login is not something self-sufficient. It is used to change state of the site. But with no reload it will not be changed. So, page reload is required anyway. or user will have to do it manually to get access to the authorized section.
Is login the only site feature that uses JQuery/AJAX? If not - why you're worrying about loading this library once, when most likely it will be loaded at every page?
There are still clients with JS disabled, for various reasons. A good web application will always let these clients in, even at cost of less functionality.
The latter is the main question, most important one. Why to choose between two? Why not to use both? - one for compatibility and another for usability?
So, I'd suggest to create basic functionality using GET to pass come codes, not messages.
And optionally improve it with some AJAX bells and whistles but with JS-based reload on succesful login anyway

Categories