octobercms / october

Self-hosted CMS platform based on the Laravel PHP Framework.
https://octobercms.com/
Other
11.01k stars 2.22k forks source link

Issue with afterCreate() model and HTML page #3368

Closed ghost closed 6 years ago

ghost commented 6 years ago

Hello,

I noticed a strange thing and I'm not sure if I found a bug or if it's the expected behavior. In all case, if it's not a bug, I think the documentation should be updated to notice that behavior.

I need to communicate with an API when I create a new model. Basically, this is to synchronize stock level between my product model and an external API.

To do that, I use the afterCreate() method of my model. I made some trace_log(), the event is correctly triggered and my $product object is available.

The problem is that, the API, for security reasons, fetch the product URL to scan some data-attributes in order to correctly create it in the external service backend.

I couldn't make it work (each time, empty product), when I tried to find what can be the cause of the problem, I noticed that the URL that contain my product component return empty value when you are on the "afterCreate()" method.

Here it the code of my html page :

<div data-sku="{{ product.sku }}" data-url="/product/{{ product.slug }}" data-stock="{{ product.stock }}" data-price="{{ product.price }}">{{ product.title }}</div>

When I visit that page, all informations are displayed correctly.

But if I put that code in my afterCreate() method :

trace_log(file_get_contents('https://mysite.com/product/'.$product->slug));

It return the HTML of the page but all data-attributes are empty.

So it seems that october CMS is unable to generate the HTML page with product attributes at this moment, even with afterCreate().

Here is how to reproduct :

If it's the expected behavior, I'm looking for a solution about how to force the HTML page generation when you are in the afterCreate() method or another event that would be more appropriate.

Best regards,

Alex

alxy commented 6 years ago

Can you confirm $product->slug yields the correct (expected) value? Also, if you visit the page using the browser, do you see the attributes beeing populated?

ghost commented 6 years ago

Hello,

Yes, the product->slug value is correct (I also trace_log($product) just before calling file_get_contents()) and all values are here.

Also, when I go to visit the product page, I can see all the data.

But when I do file_get_contents() to the same page on the afterCreate() function, it return my static HTML, but all values that are coming from my product component are empty.

jimcottrell commented 6 years ago

@Alex360hd Is this when you create a model in the OctoberCMS backend? And is the URL that you're calling out to then immediately loading a page displaying the model you've just created? I don't understand why that would be necessary, but that's the impression I'm getting, so it should be said that with October's FormController behavior, at the time afterCreate runs you're in an open database transaction. Making an external call that ends up loading your just-created model won't work until the transaction is committed.

There are a few ways you could solve this, but why wouldn't you just directly post the attributes your external API needs if you're calling out to it anyway?

ghost commented 6 years ago

Hello,

What I'm trying to do is to work with Snipcart API. I want to create the product on snipcart when I create it on october CMS backend.

Their POST call is made for that, and, as you can see in the doc, the parameter you need to pass is the url where you can find the product with it's add to cart button (fetchUrl), the snipcart system will scan this page and populate the product with the data-attributes ou have in your snipcart add to cart button.

is there a way to "force" the transaction to be commited in order to have a fetchUrl that works for the snipcart bot ? Or another event that would execute after the transaction commit ?

Thank you for your help

Alex

LukeTowers commented 6 years ago

@Alex360hd you could handle it in your controller's formAfterCreate() method: https://github.com/octobercms/october/blob/master/modules/backend/behaviors/FormController.php#L238-L246

ghost commented 6 years ago

Hello,

I used formAfterCreate() as suggested and it works like a charm. Thank you for the help !

Best regards,

Alex