diff --git a/core/lib/Thelia/Action/Cart.php b/core/lib/Thelia/Action/Cart.php index c06ade935..61629bde8 100755 --- a/core/lib/Thelia/Action/Cart.php +++ b/core/lib/Thelia/Action/Cart.php @@ -26,6 +26,10 @@ namespace Thelia\Action; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Thelia\Core\Event\ActionEvent; +use Thelia\Core\HttpFoundation\Session\Session; +use Thelia\Model\CartQuery; +use Thelia\Model\Cart as CartModel; +use Thelia\Model\Customer; class Cart implements EventSubscriberInterface @@ -91,4 +95,87 @@ class Cart implements EventSubscriberInterface "action.modifyArticle" => array("modifyArticle", 128), ); } + + public function getCart(Request $request) + { + + if(null !== $cart = $request->getSession()->getCart()){ + return $cart; + } + + if ($request->cookies->has("thelia_cart")) { + //le cookie de panier existe, on le récupère + $token = $request->cookies->get("thelia_cart"); + + $cart = CartQuery::create()->findOneByToken($token); + + if ($cart) { + //le panier existe en base + $customer = $request->getSession()->getCustomerUser(); + + if ($customer) { + if($cart->getCustomerId() != $customer->getId()) { + //le customer du panier n'est pas le mm que celui connecté, il faut cloner le panier sans le customer_id + $cart = $this->duplicateCart($cart, $request->getSession(), $customer); + } + } else { + if ($cart->getCustomerId() != null) { + //il faut dupliquer le panier sans le customer_id + $cart = $this->duplicateCart($cart, $request->getSession()); + } + } + + } else { + $cart = $this->createCart($request->getSession()); + } + } else { + //le cookie de panier n'existe pas, il va falloir le créer et faire un enregistrement en base. + $cart = $this->createCart($request->getSession()); + } + + return $cart; + } + + /** + * @param Session $session + * @return CartModel + */ + protected function createCart(Session $session) + { + $cart = new CartModel(); + $cart->setToken($this->generateCookie()); + + if(null !== $customer = $session->getCustomerUser()) { + $cart->setCustomer($customer); + } + + $cart->save(); + + $session->setCart($cart->getId()); + + return $cart; + } + + + /** + * @param CartModel $cart + * @param Session $session + * @param Customer $customer + * @return CartModel + */ + protected function duplicateCart(CartModel $cart, Session $session, Customer $customer = null) + { + $newCart = $cart->duplicate($this->generateCookie(), $customer); + $session->setCart($newCart->getId()); + + return $newCart; + } + + protected function generateCookie() + { + $id = uniqid('', true); + setcookie("thelia_cart", $id, time()+(60*60*24*365)); + + return $id; + } } diff --git a/core/lib/Thelia/Core/HttpFoundation/Session/Session.php b/core/lib/Thelia/Core/HttpFoundation/Session/Session.php index a57428c73..cde686ee4 100755 --- a/core/lib/Thelia/Core/HttpFoundation/Session/Session.php +++ b/core/lib/Thelia/Core/HttpFoundation/Session/Session.php @@ -25,13 +25,14 @@ namespace Thelia\Core\HttpFoundation\Session; use Symfony\Component\HttpFoundation\Session\Session as BaseSession; use Thelia\Core\Security\User\UserInterface; -use Thelia\Form\BaseForm; -use Thelia\Model\ConfigQuery; +use Thelia\Exception\InvalidCartException; +use Thelia\Model\CartQuery; +use Thelia\Model\Cart; use Thelia\Tools\URL; -class Session extends BaseSession { - - // -- Language ------------------------------------------------------------ +class Session extends BaseSession +{ + // -- Language ------------------------------------------------------------ public function getLocale() { @@ -47,41 +48,61 @@ class Session extends BaseSession { public function setCustomerUser(UserInterface $user) { - $this->set('customer_user', $user); + $this->set('customer_user', $user); } public function getCustomerUser() { - return $this->get('customer_user'); + return $this->get('customer_user'); } public function clearCustomerUser() { - return $this->remove('customer_user'); + return $this->remove('customer_user'); } // -- Admin user ----------------------------------------------------------- public function setAdminUser(UserInterface $user) { - $this->set('admin_user', $user); + $this->set('admin_user', $user); } public function getAdminUser() { - return $this->get('admin_user'); + return $this->get('admin_user'); } public function clearAdminUser() { - return $this->remove('admin_user'); + return $this->remove('admin_user'); + } + + // -- Error form ----------------------------------------------------------- + + /** + * @param string $formName the form name + */ + public function setErrorFormName($formName) + { + $this->set('error_form', $formName); + } + + public function getErrorFormName() + { + return $this->get('error_form', null); + } + + public function clearErrorFormName() + { + return $this->remove('error_form'); } // -- Return page ---------------------------------------------------------- public function setReturnToUrl($url) { - $this->set('return_to_url', $url); + $this->set('return_to_url', $url); } /** @@ -90,7 +111,56 @@ class Session extends BaseSession { */ public function getReturnToUrl() { - return $this->get('return_to_url', URL::getIndexPage()); + return $this->get('return_to_url', URL::getIndexPage()); + } + + // -- Cart ------------------------------------------------------------------ + + /** + * return cart if exists and is valid (checking customer) + * + * @return \Thelia\Model\Cart|null + */ + public function getCart() + { + $cart_id = $this->get("cart_id"); + $cart = null; + if ($cart_id) { + $cart = CartQuery::create()->findPk($cart_id); + try { + $this->verifyValidCart($cart); + } catch (InvalidCartException $e) { + $cart = null; + } + } + + return $cart; + } + + /** + * + * + * @param \Thelia\Model\Cart $cart + * @throws \Thelia\Exception\InvalidCartException + */ + protected function verifyValidCart(Cart $cart) + { + $customer = $this->getCustomerUser(); + if ($customer && $cart->getCustomerId() != $customer->getId()) { + throw new InvalidCartException("customer in session and customer_id in cart are not the same"); + } else if($customer === null && $cart->getCustomerId() !== null) { + throw new InvalidCartException("Customer exists in cart and not in session"); + } + } + + /** + * assign cart id in session + * + * @param $cart_id + */ + public function setCart($cart_id) + { + $this->set("cart_id", $cart_id); } } diff --git a/core/lib/Thelia/Exception/InvalidCartException.php b/core/lib/Thelia/Exception/InvalidCartException.php new file mode 100644 index 000000000..7eceb47d0 --- /dev/null +++ b/core/lib/Thelia/Exception/InvalidCartException.php @@ -0,0 +1,30 @@ +. */ +/* */ +/*************************************************************************************/ + + +namespace Thelia\Exception; + + +class InvalidCartException extends \RuntimeException { + +} \ No newline at end of file diff --git a/core/lib/Thelia/Model/Cart.php b/core/lib/Thelia/Model/Cart.php index 32f51484e..cf9b083c5 100644 --- a/core/lib/Thelia/Model/Cart.php +++ b/core/lib/Thelia/Model/Cart.php @@ -7,4 +7,30 @@ use Thelia\Model\Base\Cart as BaseCart; class Cart extends BaseCart { + public function duplicate($token, Customer $customer = null) + { + $cartItems = $this->getCartItems(); + + $cart = new Cart(); + $cart->setAddressDeliveryId($this->getAddressDeliveryId()); + $cart->setAddressInvoiceId($this->getAddressInvoiceId()); + $cart->setToken($token); + + if ($customer){ + $cart->setCustomer($customer); + } + // TODO : set current Currency + //$cart->setCurrency() + $cart->save(); + + foreach ($cartItems as $cartItem){ + $item = new CartItem(); + $item->setCart($cart); + $item->setProductId($cartItem->getProductId()); + $item->setQuantity($cartItem->getQuantity()); + $item->save(); + } + + return $cart; + } } diff --git a/core/lib/Thelia/Model/CartQuery.php b/core/lib/Thelia/Model/CartQuery.php index f0b9c48ce..1d51262d2 100644 --- a/core/lib/Thelia/Model/CartQuery.php +++ b/core/lib/Thelia/Model/CartQuery.php @@ -3,7 +3,7 @@ namespace Thelia\Model; use Thelia\Model\Base\CartQuery as BaseCartQuery; - +use Symfony\Component\HttpFoundation\Request; /** * Skeleton subclass for performing query and update operations on the 'cart' table. @@ -18,4 +18,5 @@ use Thelia\Model\Base\CartQuery as BaseCartQuery; class CartQuery extends BaseCartQuery { + } // CartQuery diff --git a/core/lib/Thelia/Model/Customer.php b/core/lib/Thelia/Model/Customer.php index 4d9a78ea0..b6379380b 100755 --- a/core/lib/Thelia/Model/Customer.php +++ b/core/lib/Thelia/Model/Customer.php @@ -116,7 +116,7 @@ class Customer extends BaseCustomer implements UserInterface protected function generateRef() { - return date("YmdHisu"); + return uniqid(substr($this->getLastname(), 0, (strlen($this->getLastname()) >= 3) ? 3 : strlen($this->getLastname())), true); } public function setPassword($password) diff --git a/core/lib/Thelia/Tests/Action/CartTest.php b/core/lib/Thelia/Tests/Action/CartTest.php new file mode 100644 index 000000000..4b9712efc --- /dev/null +++ b/core/lib/Thelia/Tests/Action/CartTest.php @@ -0,0 +1,239 @@ +. */ +/* */ +/*************************************************************************************/ +namespace Thelia\Tests\Action; + +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; +use Thelia\Core\HttpFoundation\Request; +use Thelia\Core\HttpFoundation\Session\Session; +use Thelia\Model\Cart; +use Thelia\Model\Customer; + +class CartTest extends \PHPUnit_Framework_TestCase +{ + + protected $session; + + protected $request; + + protected $actionCart; + + protected $uniqid; + + + + public function setUp() + { + $this->session = new Session(new MockArraySessionStorage()); + $this->request = new Request(); + + $this->request->setSession($this->session); + + $this->uniqid = uniqid('', true); + + $this->actionCart = $this->getMock( + "\Thelia\Action\Cart", + array("generateCookie") + ); + + $this->actionCart + ->expects($this->any()) + ->method("generateCookie") + ->will($this->returnValue($this->uniqid)); + } + + /** + * no cart present in session and cart_id no yet exists in cookies. + * + * In this case, a new cart instance must be create + */ + public function testGetCartWithoutCustomerAndWithoutExistingCart() + { + $actionCart = $this->actionCart; + + $cart = $actionCart->getCart($this->request); + + $this->assertInstanceOf("Thelia\Model\Cart", $cart, '$cart must be an instance of cart model Thelia\Model\Cart'); + $this->assertNull($cart->getCustomerId()); + $this->assertNull($cart->getAddressDeliveryId()); + $this->assertNull($cart->getAddressInvoiceId()); + $this->assertEquals($this->uniqid, $cart->getToken()); + + } + + /** + * Customer is connected but his cart does not exists yet + * + * Cart must be created and associated to the current connected Customer + */ + public function testGetCartWithCustomerAndWithoutExistingCart() + { + $actionCart = $this->actionCart; + + $request = $this->request; + + //create a fake customer just for test. If not persists test fails ! + $customer = new Customer(); + $customer->setFirstname("john"); + $customer->setLastname("doe"); + $customer->setTitleId(1); + $customer->save(); + + $request->getSession()->setCustomerUser($customer); + + $cart = $actionCart->getCart($request); + $this->assertInstanceOf("Thelia\Model\Cart", $cart, '$cart must be an instance of cart model Thelia\Model\Cart'); + $this->assertNotNull($cart->getCustomerId()); + $this->assertEquals($customer->getId(), $cart->getCustomerId()); + $this->assertNull($cart->getAddressDeliveryId()); + $this->assertNull($cart->getAddressInvoiceId()); + $this->assertEquals($this->uniqid, $cart->getToken()); + + } + + /** + * Cart exists and his id put in cookies. + * + * Must return the same cart instance + */ + public function testGetCartWithoutCustomerAndWithExistingCart() + { + $actionCart = $this->actionCart; + + $request = $this->request; + $uniqid = uniqid("test1", true); + //create a fake cart in database; + $cart = new Cart(); + $cart->setToken($uniqid); + $cart->save(); + + $request->cookies->set("thelia_cart", $uniqid); + + $getCart = $actionCart->getCart($request); + $this->assertInstanceOf("Thelia\Model\Cart", $getCart, '$cart must be an instance of cart model Thelia\Model\Cart'); + $this->assertNull($getCart->getCustomerId()); + $this->assertNull($getCart->getAddressDeliveryId()); + $this->assertNull($getCart->getAddressInvoiceId()); + $this->assertEquals($cart->getToken(), $getCart->getToken()); + } + + /** + * a cart id exists in cookies but this id does not exists yet in databases + * + * a new cart must be created (different token) + */ + public function testGetCartWithExistingCartButNotGoodCookies() + { + $actionCart = $this->actionCart; + + $request = $this->request; + + $token = "WrongToken"; + $request->cookies->set("thelia_cart", $token); + + $cart = $actionCart->getCart($request); + $this->assertInstanceOf("Thelia\Model\Cart", $cart, '$cart must be an instance of cart model Thelia\Model\Cart'); + $this->assertNull($cart->getCustomerId()); + $this->assertNull($cart->getAddressDeliveryId()); + $this->assertNull($cart->getAddressInvoiceId()); + $this->assertNotEquals($token, $cart->getToken()); + } + + /** + * cart and customer already exists. Cart and customer are linked. + * + * cart in session must be return + */ + public function testGetCartWithExistingCartAndCustomer() + { + $actionCart = $this->actionCart; + + $request = $this->request; + + + //create a fake customer just for test. If not persists test fails ! + $customer = new Customer(); + $customer->setFirstname("john"); + $customer->setLastname("doe"); + $customer->setTitleId(1); + $customer->save(); + + $uniqid = uniqid("test2", true); + //create a fake cart in database; + $cart = new Cart(); + $cart->setToken($uniqid); + $cart->setCustomer($customer); + $cart->save(); + + $request->cookies->set("thelia_cart", $uniqid); + + $request->getSession()->setCustomerUser($customer); + + $getCart = $actionCart->getCart($request); + $this->assertInstanceOf("Thelia\Model\Cart", $getCart, '$cart must be an instance of cart model Thelia\Model\Cart'); + $this->assertNotNull($getCart->getCustomerId()); + $this->assertNull($getCart->getAddressDeliveryId()); + $this->assertNull($getCart->getAddressInvoiceId()); + $this->assertEquals($cart->getToken(), $getCart->getToken(), "token must be the same"); + $this->assertEquals($customer->getId(), $getCart->getCustomerId()); + } + + /** + * Customer is connected but cart not associated to him + * + * A new cart must be created (duplicated) containing customer id + */ + public function testGetCartWithExistinsCartAndCustomerButNotSameCustomerId() + { + $actionCart = $this->actionCart; + + $request = $this->request; + + + //create a fake customer just for test. If not persists test fails ! + $customer = new Customer(); + $customer->setFirstname("john"); + $customer->setLastname("doe"); + $customer->setTitleId(1); + $customer->save(); + + $uniqid = uniqid("test3", true); + //create a fake cart in database; + $cart = new Cart(); + $cart->setToken($uniqid); + + $cart->save(); + + $request->cookies->set("thelia_cart", $uniqid); + + $request->getSession()->setCustomerUser($customer); + + $getCart = $actionCart->getCart($request); + $this->assertInstanceOf("Thelia\Model\Cart", $getCart, '$cart must be an instance of cart model Thelia\Model\Cart'); + $this->assertNotNull($getCart->getCustomerId()); + $this->assertNull($getCart->getAddressDeliveryId()); + $this->assertNull($getCart->getAddressInvoiceId()); + $this->assertNotEquals($cart->getToken(), $getCart->getToken(), "token must be different"); + $this->assertEquals($customer->getId(), $getCart->getCustomerId()); + } + +} \ No newline at end of file diff --git a/core/lib/Thelia/Tests/Command/BaseCommandTest.php b/core/lib/Thelia/Tests/Command/BaseCommandTest.php index ca9d0a632..356478ab9 100644 --- a/core/lib/Thelia/Tests/Command/BaseCommandTest.php +++ b/core/lib/Thelia/Tests/Command/BaseCommandTest.php @@ -1,12 +1,25 @@ . */ +/* */ +/*************************************************************************************/ namespace Thelia\Tests\Command; diff --git a/core/lib/Thelia/Tests/Core/HttpFoundation/Session/SessionTest.php b/core/lib/Thelia/Tests/Core/HttpFoundation/Session/SessionTest.php new file mode 100644 index 000000000..67fbfd1c2 --- /dev/null +++ b/core/lib/Thelia/Tests/Core/HttpFoundation/Session/SessionTest.php @@ -0,0 +1,136 @@ +. */ +/* */ +/*************************************************************************************/ + +namespace Thelia\Tests\Core\HttpFoundation\Session; + +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; +use Thelia\Core\HttpFoundation\Session\Session; +use Thelia\Model\Cart; +use Thelia\Model\Customer; + +class SessionTest extends \PHPUnit_Framework_TestCase +{ + + protected $session; + + public function setUp() + { + $this->session = new Session(new MockArraySessionStorage()); + } + + public function testGetCartWithoutExistingCart() + { + $session = $this->session; + + $cart = $session->getCart(); + + $this->assertNull($cart); + } + + public function testGetCartWithExistingCartWithoutCustomerConnected() + { + $session = $this->session; + + $testCart = new Cart(); + $testCart->setToken(uniqid("testSessionGetCart1", true)); + $testCart->save(); + + $session->setCart($testCart->getId()); + + $cart = $session->getCart(); + + $this->assertNotNull($cart); + $this->assertInstanceOf("\Thelia\Model\Cart", $cart, '$cart must be an instance of Thelia\Model\Cart'); + $this->assertEquals($testCart->getToken(), $cart->getToken()); + + } + + public function testGetCartWithExistingCustomerButNoCart() + { + $session = $this->session; + + //create a fake customer just for test. If not persists test fails ! + $customer = new Customer(); + $customer->setFirstname("john test session"); + $customer->setLastname("doe"); + $customer->setTitleId(1); + $customer->save(); + + $session->setCustomerUser($customer); + + $cart = $session->getCart(); + + $this->assertNull($cart); + } + + public function testGetCartWithExistingCartAndCustomerButWithoutReferenceToCustomerInCart() + { + $session = $this->session; + + //create a fake customer just for test. If not persists test fails ! + $customer = new Customer(); + $customer->setFirstname("john test session"); + $customer->setLastname("doe"); + $customer->setTitleId(1); + $customer->save(); + + $session->setCustomerUser($customer); + + $testCart = new Cart(); + $testCart->setToken(uniqid("testSessionGetCart2", true)); + $testCart->save(); + + $session->setCart($testCart->getId()); + + $cart = $session->getCart(); + + $this->assertNull($cart); + } + + public function testGetCartWithExistingCartAndCustomerAndReferencesEachOther() + { + $session = $this->session; + + //create a fake customer just for test. If not persists test fails ! + $customer = new Customer(); + $customer->setFirstname("john test session"); + $customer->setLastname("doe"); + $customer->setTitleId(1); + $customer->save(); + + $session->setCustomerUser($customer); + + $testCart = new Cart(); + $testCart->setToken(uniqid("testSessionGetCart3", true)); + $testCart->setCustomerId($customer->getId()); + $testCart->save(); + + $session->setCart($testCart->getId()); + + $cart = $session->getCart(); + + $this->assertNotNull($cart); + $this->assertInstanceOf("\Thelia\Model\Cart", $cart, '$cart must be an instance of Thelia\Model\Cart'); + } + +} \ No newline at end of file