mirror of
https://github.com/kevin-DL/LaravelShoppingcart.git
synced 2026-01-11 18:54:33 +00:00
Added a new associate method, to associate a row in the cart with a model, so you can access the model from the CartRowCollection
This commit is contained in:
31
README.md
31
README.md
@@ -37,6 +37,7 @@ Look at one of the following topics to learn more about LaravelShoppingcart
|
||||
* [Usage](#usage)
|
||||
* [Collections](#collections)
|
||||
* [Instances](#instances)
|
||||
* [Associate a model](#models)
|
||||
* [Exceptions](#exceptions)
|
||||
* [Events](#events)
|
||||
* [Example](#example)
|
||||
@@ -220,6 +221,35 @@ N.B. Keep in mind that the cart stays in the last set instance for as long as yo
|
||||
|
||||
N.B.2 The default cart instance is called `main`, so when you're not using instances,`Cart::content();` is the same as `Cart::instance('main')->content()`.
|
||||
|
||||
## Associate a model
|
||||
A new feature is associating a model with the items in the cart. Let's say you have a `Product` model in your application. With the new `associate()` method, you can tell the cart that an item in the cart, is associated to the `Product` model.
|
||||
|
||||
That way you can access your model right from the `CartRowCollection`!
|
||||
|
||||
Here is an example:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Let say we have a Product model that has a name and description.
|
||||
*/
|
||||
|
||||
Cart::associate('Product')->add('293ad', 'Product 1', 1, 9.99, array('size' => 'large'));
|
||||
|
||||
|
||||
$content = Cart::content();
|
||||
|
||||
|
||||
foreach($content as $row)
|
||||
{
|
||||
echo 'You have ' . $row->qty . ' items of ' . $row->product->name . ' with description: "' . $row->product->description . '" in your cart.';
|
||||
}
|
||||
```
|
||||
|
||||
The key to access the model is the same as the model name you associated (lowercase).
|
||||
The `associate()` method has a second optional parameter for specifying the model namespace.
|
||||
|
||||
## Exceptions
|
||||
The Cart package will throw exceptions if something goes wrong. This way it's easier to debug your code using the Cart package or to handle the error based on the type of exceptions. The Cart packages can throw the following exceptions:
|
||||
|
||||
@@ -230,6 +260,7 @@ The Cart package will throw exceptions if something goes wrong. This way it's ea
|
||||
| *ShoppingcartInvalidPriceException* | When a not numeric price is passed |
|
||||
| *ShoppingcartInvalidQtyException* | When a not numeric quantity is passed |
|
||||
| *ShoppingcartInvalidRowIDException* | When the rowId that got passed doesn't exists in the current cart |
|
||||
| *ShoppingcartUnknownModelException* | When an unknown model is associated to a cart row |
|
||||
|
||||
## Events
|
||||
|
||||
|
||||
@@ -25,6 +25,20 @@ class Cart {
|
||||
*/
|
||||
protected $instance;
|
||||
|
||||
/**
|
||||
* The Eloquent model a cart is associated with
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $associatedModel;
|
||||
|
||||
/**
|
||||
* An optional namespace for the associated model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $associatedModelNamespace;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -55,6 +69,24 @@ class Cart {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the associated model
|
||||
*
|
||||
* @param string $modelName The name of the model
|
||||
* @param string $modelNamespace The namespace of the model
|
||||
* @return void
|
||||
*/
|
||||
public function associate($modelName, $modelNamespace = null)
|
||||
{
|
||||
$this->associatedModel = $modelName;
|
||||
$this->associatedModelNamespace = $modelNamespace;
|
||||
|
||||
if( ! class_exists($modelNamespace . '\\' . $modelName)) throw new Exceptions\ShoppingcartUnknownModelException;
|
||||
|
||||
// Return self so the method is chainable
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a row to the cart
|
||||
*
|
||||
@@ -411,7 +443,7 @@ class Cart {
|
||||
'price' => $price,
|
||||
'options' => new CartRowOptionsCollection($options),
|
||||
'subtotal' => $qty * $price
|
||||
));
|
||||
), $this->associatedModel, $this->associatedModelNamespace);
|
||||
|
||||
$cart->put($rowId, $newRow);
|
||||
|
||||
@@ -428,7 +460,6 @@ class Cart {
|
||||
protected function updateQty($rowId, $qty)
|
||||
{
|
||||
if($qty <= 0)
|
||||
if($qty == 0)
|
||||
{
|
||||
return $this->remove($rowId);
|
||||
}
|
||||
|
||||
@@ -4,9 +4,33 @@ use Illuminate\Support\Collection;
|
||||
|
||||
class CartRowCollection extends Collection {
|
||||
|
||||
public function __construct($items)
|
||||
/**
|
||||
* The Eloquent model a cart is associated with
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $associatedModel;
|
||||
|
||||
/**
|
||||
* An optional namespace for the associated model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $associatedModelNamespace;
|
||||
|
||||
/**
|
||||
* Constructor for the CartRowCollection
|
||||
*
|
||||
* @param array $items
|
||||
* @param string $associatedModel
|
||||
* @param string $associatedModelNamespace
|
||||
*/
|
||||
public function __construct($items, $associatedModel, $associatedModelNamespace)
|
||||
{
|
||||
parent::__construct($items);
|
||||
|
||||
$this->associatedModel = $associatedModel;
|
||||
$this->associatedModelNamespace = $associatedModelNamespace;
|
||||
}
|
||||
|
||||
public function __get($arg)
|
||||
@@ -16,10 +40,18 @@ class CartRowCollection extends Collection {
|
||||
return $this->get($arg);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
if($arg == strtolower($this->associatedModel))
|
||||
{
|
||||
$modelInstance = $this->associatedModelNamespace ? $this->associatedModelNamespace . '\\' .$this->associatedModel : $this->associatedModel;
|
||||
$model = new $modelInstance;
|
||||
|
||||
return $model->find($this->id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function search(Array $search)
|
||||
public function search(array $search)
|
||||
{
|
||||
foreach($search as $key => $value)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php namespace Gloudemans\Shoppingcart\Exceptions;
|
||||
|
||||
class ShoppingcartUnknownModelException extends \Exception {}
|
||||
@@ -6,7 +6,9 @@ use Gloudemans\Shoppingcart\CartRowCollection;
|
||||
use Gloudemans\Shoppingcart\CartRowOptionsCollection;
|
||||
use Mockery as m;
|
||||
|
||||
require_once 'SessionMock.php';
|
||||
require_once __DIR__.'/helpers/SessionMock.php';
|
||||
require_once __DIR__.'/helpers/ProductModelStub.php';
|
||||
require_once __DIR__.'/helpers/NamespacedProductModelStub.php';
|
||||
|
||||
class CartTest extends PHPUnit_Framework_TestCase {
|
||||
|
||||
@@ -299,4 +301,46 @@ class CartTest extends PHPUnit_Framework_TestCase {
|
||||
$this->assertInstanceOf('Gloudemans\Shoppingcart\CartRowOptionsCollection', $this->cart->content()->first()->options);
|
||||
}
|
||||
|
||||
public function testCartCanAssociateWithModel()
|
||||
{
|
||||
$this->cart->associate('TestProduct');
|
||||
|
||||
$this->assertEquals('TestProduct', PHPUnit_Framework_Assert::readAttribute($this->cart, 'associatedModel'));
|
||||
}
|
||||
|
||||
public function testCartCanAssociateWithNamespacedModel()
|
||||
{
|
||||
$this->cart->associate('TestProduct', 'Acme\Test\Models');
|
||||
|
||||
$this->assertEquals('TestProduct', PHPUnit_Framework_Assert::readAttribute($this->cart, 'associatedModel'));
|
||||
$this->assertEquals('Acme\Test\Models', PHPUnit_Framework_Assert::readAttribute($this->cart, 'associatedModelNamespace'));
|
||||
}
|
||||
|
||||
public function testCartCanReturnModelProperties()
|
||||
{
|
||||
$this->events->shouldReceive('fire')->once()->with('cart.add', m::type('array'));
|
||||
|
||||
$this->cart->associate('TestProduct')->add('293ad', 'Product 1', 1, 9.99);
|
||||
|
||||
$this->assertEquals('This is the description of the test model', $this->cart->get('8cbf215baa3b757e910e5305ab981172')->testproduct->description);
|
||||
}
|
||||
|
||||
public function testCartCanReturnNamespadedModelProperties()
|
||||
{
|
||||
$this->events->shouldReceive('fire')->once()->with('cart.add', m::type('array'));
|
||||
|
||||
$this->cart->associate('TestProduct', 'Acme\Test\Models')->add('293ad', 'Product 1', 1, 9.99);
|
||||
|
||||
$this->assertEquals('This is the description of the namespaced test model', $this->cart->get('8cbf215baa3b757e910e5305ab981172')->testproduct->description);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Gloudemans\Shoppingcart\Exceptions\ShoppingcartUnknownModelException
|
||||
*/
|
||||
public function testCartThrowsExceptionOnUnknownModel()
|
||||
{
|
||||
$this->cart->associate('NoneExistingModel');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
5
tests/helpers/NamespacedProductModelStub.php
Normal file
5
tests/helpers/NamespacedProductModelStub.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php namespace Acme\Test\Models;
|
||||
class TestProduct {
|
||||
public $description = 'This is the description of the namespaced test model';
|
||||
public function find($id) { return $this; }
|
||||
}
|
||||
6
tests/helpers/ProductModelStub.php
Normal file
6
tests/helpers/ProductModelStub.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
class TestProduct {
|
||||
public $description = 'This is the description of the test model';
|
||||
public function find($id) { return $this; }
|
||||
}
|
||||
Reference in New Issue
Block a user