EvShop Plugin

Short Description: 
This is a basic ecommerce plugin that provides a generalised set of functions. It is designed in a way which allows the functionality to be EXTENDED WITHOUT EDITING THE ORIGINAL PLUGIN. This will allow for easy bug fixing as the whole plugin can be overridden. 

Feature Set: 
	- Products
		- Products can have multiple variants based on the product attributes 
			* If no product attributes are configured then each product will only have one "invisible" variant
		- Product attributes are set on a global level but which attributes are applicable is set at a product level
	- Product Listing page 
		- Has functionality for showing all products, with the lowest available price
		- Product filtering/search
	- Relatable Items plugin allows for products to be easily associated with other models such as Brands, Categories, Manufacturer etc. (See section on "Adding Related Items")

	- Product Helper to provide funcitons for handling: 
		- product url 
		- product image

Working Examples: 

	This plugin was originally built for "Discount Beds" and "Mentor Training" so these are a good place to start when looking how to extend and use this plugin. 

Upgrading Versions: 

	Most upgrades will not break exisiting functionality but if it does then a readme should be added to the repository in the format of "1.3.x to 1.4.x" specifying the procedure for upgrades, including any database changes and migrations which need to be applied.


Section: Installation 
	
	The following plugins are required for EvShop to run. If you are using Composer for install the dependencies will be added
	automattically when you run "Console/cake composer.c require evoluted/shop"
		- EvShop
		- EvCheckout
		- SearchIndex
		- EvCategory
		- EvRelatedItems
		- CakeDC/Migrations 

	bootstrap.php 

		CakePlugin::load('EvShop', array(
			'routes' => true,
			'bootstrap' => true
		));

	Add the following helpers 

		'EvShop.Product'

	Setup the database 

		- This plugin has been setup to use the CakeDC Migrations plugin. This allows for easy setup of the database schema and allows for painless migration when database changes are made during an upgrade. 

		- To run the migrations and setup the database run 

			"Console/cake Migrations.migration run all --plugin EvShop"

			Side Note: Migrations will also need to be run for the other required plugins


Section: Extending Functionality
	
	Every shop generally has a different set of features/functionality with this in mind we have made it as easy as possible (as we can with CAKEPHP) to extend the functionality given and add your own. 

	1. To overide the functionality of the ProductsController use the following steps: 
	
		- Create a new product controller
				app/Controllers/AppProductsController.php 

		- Add the following content

				<?php 

					App::uses('ProductsController', 'EvShop.Controller');

					/**
					 * Extended products controller
					 *
					 * @package       app.Controller
					 */
					class AppProductsController extends ProductsController {

					}

		- Update routes to point at the new controller

		- Extending the ProductHelper to update the product urls 

			- Create a new Helper 
				app/View/Helper/ProductExtHelper.php 

			- Add the following content 

				<?php

					App::uses('ProductHelper', 'EvShop.View/Helper');

					class ProductExtHelper extends ProductHelper {

					/**
					 * Returns the route for the given product in a form to Router::url
					 * EXTENDED BECAUSE: The route needs to point to the overrride controller
					 * @param 	array $product The product array 
					 * @return 	array The url array
					 */
						public function getProductRoute($product) {

							//Extract ID
							$productId = $this->_getProductId($product);

							return array(
								'plugin' => false, 
								'controller' => 'app_products', 
								'action' => 'view', 
								$productId
							); 

						}

					}

			- Update the helper in AppController to point at the new helper

				'EvShop.Product' => array(
					'className' => 'ProductExt'
				),

			- Override the routes 

				In order to get CAKEPHP to point at the correct Controller you also need to update the routes, 
				To do this copy all the routes out from 
				
					plugins/EvShop/Config/routes.php 
				
				into 

					app/Config/route.php

				and update to point at the new controller


	2. To extend model functionality 

		In order to extend the model functionality you need to extend the ProductsController as per the instructions above with the following additional steps 

		- Create a new model "AppProduct"
			app/Model/AppProduct.php 

		- Add the following content 

			<?php

				App::uses('Product', 'EvShop.Model');

				class AppProduct extends Product {

					//Needed to set up in place of Product Model if we want to use the same table
					public $useTable = 'products';
					public $alias = 'Product';
					public $name = 'Product';

				}

		- Tell the Controller to use this model instead of the original 

			Add the following line at the top of AppProductsController 

				public $uses = "AppProduct";

			This will tell the controller to use our extended Model instead of the original 

		- Add in your modifications


Section: Adding Related Items 

	Adding related items requires the Product Model to be extended as per the instructions in "Extending Functionality"

	Once you have an AppProduct model you would add the following to add related products and brand

		public $actsAs = array(
			'EvRelatedItems.Relatable' => array(
				'models' => array(
					'EvCategory.Category' => array(

					),
					'EvShop.Product' => array(
						'contain' => array(
							'Image' => array('limit' => 1),
							'ListingImage' => array('limit' => 1)	
						)
					),
					'EvShop.Brand' => array(
						'multiple' => false, 
						'empty' => true,
						'contain' => array(
							'Image' => array('limit' => 1)
						)
					),
				)
			)
		);

	This will automattically pull these out on the front and backend of the site in the readForEdit

	To populate the selects in the admin area all the following to your AppProductsController 


		/**
		 * Used to populate form drop down selects
		 *
		 * Override in your controller to customise
		 */
			protected function _adminPopulateLookups() {

				parent::_adminPopulateLookups();

				$Product = $this->{$this->modelClass};
				$this->set('relatedBrands', $Product->RelatedBrand->find('list'));
				$this->set('relatedProducts', $Product->find('list'));
				
			}


Section: Product Attributes 


Section: Adding custom fields to products  

	Once installed custom fields can be added to products and attributes by adding them as fields in the database. 
	The plugin uses Model::schema() to pull in the database fields and show them in the admin form. 

	In order to customise the way these fields are displayed in the admin you can override the EvCoreController::_adminFormFields() method   

Section: Custom Product Filters 

	The Product model allows for additional product filters to be added easily. 

	1. When passing your search params to Product::readForListingQuery($filters = array()) 
		If you pass it a param it does not know how to handle, e.g.
			
			$filters = array(
				'brand' => '4'
			)

		It will look for a method with the following function declaration

			protected function _filterBy[Param]Query($filterParams, $query = array())

		e.g.

			protected function _filterByBrandQuery($filterParams, $query = array()) 

		Where 
			$filterParams -	is the value of the param (in the example above = 4) 
							but could equally be an array

			$query - 		Is the find params for the product search. 

		This allows you to amend the product search by returning the amended query array

			/**
			* Helper function to build the query params needed to filter products by category
			* @param  mixed $filterParams 	This is the parameters as passed into readForListingQuery
			* @param  array  $query  		The find params so far to append to 
			* @return array                The initail find params with parts added for category filtering
			*/
				protected function _filterByBrandQuery($filterParams, $query = array()) {

					$query['joins'][] = array(
						'table' => 'ev_related_items_related_items', 
						'alias' => 'RelatedBrand', 
						'type' => 'RIGHT',
						'conditions' => array(
							'RelatedBrand.model_id = Product.id', 
							'RelatedBrand.model' => 'Product',
							'RelatedBrand.related_model' => 'Brand'
						)
					);

					$query['conditions']['RelatedBrand.related_model_id'] = $filterParams;
					
					return $query;

				}


Section: Sessions and Configuration variables
	
	Session Variables
		
	Settings

		- EvShop.prices_include_vat - Indicates whether the prices in the admin include or exclude vat


Section: Future plans

	- Add menu items into the admin on installation
	- Add file based indexing/caching for product filters to speed up frontend