After looking around the internet for days, i decided to ask your help here.
I got a problem with Zend Framework 2 session container management. I don't understand why, but the framework emptied all my containers each time i'm changing page.
My case is simple, i'm building an online shop :
The customer is on a product and click the "add to cart" button
The product is saved to session
The customer get back to the products list to choose another product ... but there is no product anymore in his cart.
Here is a piece of code :
// Create container to add product
$container = new Zend\Session\Container('frontCart');
// Add product to cart
$container->offsetSet('frontCartContent',
array(1 => serialize($my_product_object));
If i make a debug of the session just after added :
Debug::dump($_SESSION);
// Display this :
["frontCart"] => object(Zend\Stdlib\ArrayObject)#70 (4) {
["storage":protected] => array(1) {
["frontCartContent"] => array(1) {
[1] => string(1175) "my serialized product object"
}
}
["flag":protected] => int(2)
["iteratorClass":protected] => string(13) "ArrayIterator"
["protectedProperties":protected] => NULL
}
Then, if i simply reload the page, or if switch from :
http://mydomain.com/products_list/my_product
to
http://mydomain.com/products_list
I get :
Debug::dump($_SESSION);
// Display this :
["frontCart"] => NULL
Please, help :-(
I don't understand at all why ZF2 has this behavior, and this is very problematic for an online shop customer if he can't add and by products.
Thx
EDIT
Following Tim's demand here is more code.
I initialize my session container in the controller's constructor
public function __construct()
{
if (!$this->sessionCart)
{
$this->sessionCart = new Container(ConstantSession::FRONT_CART);
}
}
Then, here is the exact way i'm adding the product to the container
$this->sessionCart->offsetSet(ConstantSession::FRONT_CART_CONTENT,
array($cartNumber => serialize($product))
);
$cartNumber is incremented following the number of products in the cart (when it'll work).
$product is an object with all its properties.
EDIT 2
Following Tim's advises i changed my "add to cart" code to :
$this->sessionCart->frontCartContent = array($cartNumber => $product);
When i want to get back my session content i create a new instance of Container :
// Init new container
$container = new Zend\Session\Container('frontCart');
// Get the content
$container->frontCartContent;
If i make a Debug::dump() of the last line, i still get NULL after changing page.
There are a few issues with your code. Try:
// Create container to add product
$container = new Zend\Session\Container('cart');
// Add product to cart
$container->frontCartContent = array($my_product_object);
then on the other page, you need to create the container again with the same parameter you used above, and then check the contents. Don't just called $_SESSION:
$container = new Zend\Session\Container('cart');
var_dump($container->frontCartContent);
See if that gives you better results.
Related
I use laravel 5.3
I created an online store website.
If user logs in and chooses a product then okay button, there will be realtime notification in icon cart.
My code looks like this :
If user selects product and okay button, it will run this function :
public function addNotificationCart()
{
Notification::send(auth()->user(), new CartNotification($cart));
}
Then :
public function toBroadcast($notifiable) {
return new BroadcastMessage([
'id' => $this->data->id,
'time' => $this->data->created_at,
'group' => 'cart'
]);
}
And my javascript code looks like this :
Echo.private('App.User.' + window.Laravel.authUser.id).notification((notification) => {
// run this statement if exist notification
})
If the code run, it works
I want to add a new feature on my website. So when the user is not logged in, the user can also add cart and there is will display notification cart
What matters to me is how I do it?
In this section :
Notification::send(auth()->user(), new CartNotification($cart));
And :
window.Laravel.authUser.id
It requires user data being logged and id
How do I fill it if the user is not logged on?
I am building a pretty simple online shop in SilverStripe. I am writing a function to remove an item from the cart (order in my case).
My setup:
My endpoint is returning JSON to the view for use in ajax.
public function remove() {
// Get existing order from SESSION
$sessionOrder = Session::get('order');
// Get the product id from POST
$productId = $_POST['product'];
// Remove the product from order object
unset($sessionOrder[$productId]);
// Set the order session value to the updated order
Session::set('order', $sessionOrder);
// Save the session (don't think this is needed, but thought I would try)
Session::save();
// Return object to view
return json_encode(Session::get('order'));
}
My issue:
When I post data to this route, the product gets removed but only temporarily, then next time remove is called, the previous item is back.
Example:
Order object:
{
product-1: {
name: 'Product One'
},
product-2: {
name: 'Product Two'
}
}
When I post to remove product-1 I get the following:
{
product-2: {
name: 'Product Two'
}
}
Which appears to have worked but then I try and remove product-2 with and get this:
{
product-1: {
name: 'Product One'
}
}
The SON OF A B is back! When I retrieve the entire cart, it still contains both.
How do I get the order to stick?
Your expectation is correct, and it should work with the code you wrote. However, the way the session data is managed doesn't work well with data being deleted, because it is not seen as a change of state. Only existing data being edited is seen as such. See Session::recursivelyApply() if you want to know more.
Only way I know is to (unfortunately) emphasized textmanipulate $_SESSION directly before you set the new value for 'order'
public function remove() {
// Get existing order from SESSION
$sessionOrder = Session::get('order');
// Get the product id from POST
$productId = $_POST['product'];
// Remove the product from order object
unset($sessionOrder[$productId]);
if (isset($_SESSION['order'])){
unset($_SESSION['order']);
}
// Set the order session value to the updated order
Session::set('order', $sessionOrder);
// Return object to view
return json_encode(Session::get('order'));
}
i'm trying to introduce an additional step in the one step checkout process (at the start, just after login). This is on Magento v1.8 and the items being sold are virtual product types (therefore the only sections that should appear at checkout are: [new section], billing, payment, and order review.
I've had a look at a number of articles - this one being most suited to my needs (albeit written for v1.4 i think, and uses a the overloading of existing pages instead of writing a new module). I've also followed along with this article however it aims to introduce a module - something which I don't think is absolutely required for this. SO article Magento Adding Step to Onepage Checkout was also referenced.
My problem:
I have the additional step appearing on the OPC page, however the accordion which should be expanding the active section isn't. This is due to the CSS class active not being set, which is in turn not set since the new module is not marked as active.
My question:
What have I missed from the steps below to ensure that the new module is set as the ActiveStep?
What I've attempted to so far:
In short, I've introduced <?php echo $this->getActiveStep(); ?>statement on onepage.phtml and it's indicating that 'billing' is still the active page (the default first page).
I've made the following changes so far specifically around the ordering of pages:
added the new section (registerkids) to _getStepCodes() in abstract.php
return array('login', 'registerkids', 'billing', 'shipping', 'shipping_method', 'payment', 'review');
created a app/code/local file in Checkout/Block/Onepage/registerkids.php with
class Mage_Checkout_Block_Onepage_Registerkids extends Mage_Checkout_Block_Onepage_Abstract
{
protected function _construct()
{
$this->getCheckout()->setStepData('registerkids', array(
'label' => Mage::helper('checkout')->__('Assign your kids to the booking'),
'is_show' => $this->isShow()
));
if ($this->isCustomerLoggedIn()) {
$this->getCheckout()->setStepData('registerkids', 'allow', true);
}
parent::_construct();
}
}
removed the if ($this->isCustomerLoggedIn()) statement from Checkout\Block\Onepage\billing.php that sets the next step
updated Checkout\Model\Type\Onepage.php initCheckout() with
if (!($step==='login' || $customerSession->isLoggedIn() && $step==='registerkids')) {
$checkout->setStepData($step, 'allow', false); // where 'registerkids' used to say 'billing'
made the following changes to opcheckout.js -
this.steps = ['login', 'registerkids', 'billing', 'shipping', 'shipping_method', 'payment', 'review']; (added new section)
this.currentStep = 'registerkids';
updated setMethod: function() so that next section after login is this.gotoSection('registerkids', true);
updated template/persistent/checkout/onepage/login.phtml JS customMethod() to checkout.gotoSection('registerkids');
updated Checkout/Onepage.php getActiveStep() to return $this->isCustomerLoggedIn() ? 'registerkids' : 'login';
after quite a bit of investigation, the function that controls the initial Active step is:
public function getActiveStep()
{
return $this->isCustomerLoggedIn() ? 'yoursection' : 'login';
}
this can be found in Mage\Checkout\Block\Onepage.php, and the function that calls it from onepage.phtml is $this->getActiveStep()
The reason it wasn't working for me was that the file was in the wrong place. Working fine now.
Hope this helps someone
I'm trying to make new product statuses but i can't figure out how to do it and all the stuff set on the web is not consistent or simply talks about order status which i don't want to change.
What is your motivation to have new product statuses? I think it's little bit risky to change this part of app. I suggest you to add new attribute and use this one instead system product's attribute 'status', this attribute tells to system if product is enabled or disabled. I guess there is nothing between :)
Override class Mage_Catalog_Model_Product_Status to the local folder. Then open the file
\app\code\local\Mage\Catalog\Model\Product\Status.php
At the top of the file you can see the constants
const STATUS_ENABLED = 1;
const STATUS_DISABLED = 2;
Add your custom status below them, for example
const STATUS_SUSPENDED = 3;
Then edit the function getOptionArray
static public function getOptionArray()
{
return array(
self::STATUS_ENABLED => Mage::helper('catalog')->__('Enabled'),
self::STATUS_DISABLED => Mage::helper('catalog')->__('Disabled'),
self::STATUS_SUSPENDED => Mage::helper('catalog')->__('Suspended')
);
}
That's it. Don't forget to clear the cache.
I have created a script to update programmatically my products pictures but my script delete all tier_prices on $product->save();
Here is my bilder update script :
foreach ($productCollection as $product) {
$formatted_sku = $product->getSku();
$config = $product->getMediaConfig();
// JPG files verification
$jpg_file = $images_folder.$formatted_sku.".".$extension[0];
if (file_exists($jpg_file) ) {
$fileurl = $config->getMediaUrl($jpg_file);
$product->addImageToMediaGallery($jpg_file, $visibility, false, false);
$product->save();
}
}
How can I avoid the update of my tier_prices ?
Thanks a lot.
For those of you that are still running into this issue, there is a simple fix to try. It looks like the tierprice data is not read by the default getModel for the product. To fix this, just call the product's getTierPrice method to load it.
$tp=$product->getTierPrice();
You don't have to do anything else, just load it. Then when you save the product, the tiered pricing data is saved.
I run into the same problem. I finally work it out in a very weird way, but it definitely worked. You just need to create a "fake" tierprice:
$tierPrices = array(
'website_id' => 0,
'cust_group' => 2,
'price_qty' => 3,
'price' => 10
);
(note that there are no [ ])
Then add it (it won't add anything actually), but you need to do this:
$product->setTierPrice($tierPrices);
And finally save the product:
$product->save();
It will save your product without deleting your old tier prices. Hope it helps!!
How do you created that $productCollection? Maybe product was not populated with needed data (tier_prices) so save() persist product without that data. Try to add some attributes to select with addAttributeToSelect()
The comments of others on this post helped to lead me to a solution that worked. For me, simply setting the tier price to false is what was needed to prevent it from being overwritten/modified.
$product->setTierPrice(false);
I personally prefer this option over some of the other solutions as it's clean, simple, doesn't set fake values, and it works. To those points, I would have preferred it if the solution presented by GregC would have worked as it's simply loading the tier price, but in my testing that did not work as expected - the tier price was still deleted.
Here would be the modified version of the code from the OP.
foreach ($productCollection as $product) {
$formatted_sku = $product->getSku();
$config = $product->getMediaConfig();
// JPG files verification
$jpg_file = $images_folder.$formatted_sku.".".$extension[0];
if (file_exists($jpg_file) ) {
$fileurl = $config->getMediaUrl($jpg_file);
$product->addImageToMediaGallery($jpg_file, $visibility, false, false);
$product->setTierPrice(false); // set tier price to false to prevent it from being overwritten
$product->save();
}
}
This code was tested and used with Magento EE 1.14.12.0