I tried attaching Product.php and ProductGroup.php to the last post but it came back with a server error so here they are :)
Product.php
<?php
/**
* This is a standard Product page-type with fields like
* Price, Weight, Model/Author and basic management of
* groups.
*
* It also has an associated Product_OrderItem class,
* an extension of OrderItem, which is the mechanism
* that links this page type class to the rest of the
* eCommerce platform. This means you can add an instance
* of this page type to the shopping cart.
*
* @package ecommerce
*/
class Product extends Page {
public static $db = array(
'WebLink' => 'Varchar(30)',
'DateAdded' => 'Date',
'Testimonial' => 'HTMLText',
);
public static $has_one = array(
'Image' => 'Product_Image'
);
public static $has_many = array(
'Variations' => 'ProductVariation'
);
public static $many_many = array(
'ProductGroups' => 'ProductGroup'
);
public static $belongs_many_many = array();
public static $singular_name = 'Product';
public static $plural_name = 'Products';
static $default_parent = 'ProductGroup';
static $default_sort = 'Title ASC';
static $add_action = 'a Product Page';
static $icon = 'ecommerce/images/icons/package';
function getCMSFields() {
$fields = parent::getCMSFields();
// Standard product detail fields
$fields->addFieldToTab('Root.Content.Main',new TextField('WebLink'),'Content');
$fields->addFieldToTab('Root.Content.Main',new HtmlEditorField('Testimonial'),'Content');
$datefield = new DateField('DateAdded');
$datefield->setConfig('showcalendar', true);
$datefield->setConfig('showdropdown', true);
$datefield->setConfig('dateformat', 'dd/MM/YYYY');
$fields->addFieldToTab('Root.Content.Main', $datefield, 'Content');
if(!$fields->dataFieldByName('Image')) {
$fields->addFieldToTab('Root.Content.Images', new ImageField('Image', _t('Product.IMAGE', 'Product Image')));
}
// Flags for this product which affect it's behaviour on the site
$fields->addFieldsToTab(
'Root.Content.Product Groups',
array(
new HeaderField(_t('Product.ALSOAPPEARS', 'This product also appears in the following groups')),
$this->getProductGroupsTable()
)
);
return $fields;
}
function getVariationsTable() {
$singleton = singleton('ProductVariation');
$query = $singleton->buildVersionSQL("`ProductID` = '{$this->ID}'");
$variations = $singleton->buildDataObjectSet($query->execute());
$filter = $variations ? "`ID` IN ('" . implode("','", $variations->column('RecordID')) . "')" : "`ID` < '0'";
//$filter = "`ProductID` = '{$this->ID}'";
}
protected function getProductGroupsTable() {
$tableField = new ManyManyComplexTableField(
$this,
'ProductGroups',
'ProductGroup',
array(
'Title' => 'Product Group Page Title'
)
);
$tableField->setPageSize(12);
$tableField->setPermissions(array());
//TODO: use a tree structure for selecting groups
//$field = new TreeMultiselectField('ProductGroups','Product Groups','ProductGroup');
return $tableField;
}
/**
* Enables developers to completely turning off the ability to purcahse products.
*/
/**
* Recaulculates the number sold for all products. This should be run as a cron job perhaps daily.
*/
//passing on shopping cart links ...is this necessary?? ...why not just pass the cart?
/**
* When the ecommerce module is first installed, and db/build
* is invoked, create some default records in the database.
*/
}
class Product_Controller extends Page_Controller {
function init() {
parent::init();
Requirements::themedCSS('Product');
Requirements::themedCSS('ProductGroup');
}
}
class Product_Image extends Image {
public static $db = array();
public static $has_one = array();
public static $has_many = array();
public static $many_many = array();
public static $belongs_many_many = array();
//default image sizes
protected static $thumbnail_width = 225;
protected static $thumbnail_height = 150;
protected static $content_image_width = 225;
protected static $large_image_width = 600;
function set_thumbnail_size($width = 225, $height = 150){
self::$thumbnail_width = $width;
self::$thumbnail_height = $height;
}
function set_content_image_width($width = 200){
self::$content_image_width = $width;
}
function set_large_image_width($width = 600){
self::$large_image_width = $width;
}
function generateThumbnail($gd) {
$gd->setQuality(80);
return $gd->paddedResize(self::$thumbnail_width,self::$thumbnail_height);
}
function generateContentImage($gd) {
$gd->setQuality(90);
return $gd->resizeByWidth(self::$content_image_width);
}
function generateLargeImage($gd) {
$gd->setQuality(90);
return $gd->resizeByWidth(self::$large_image_width);
}
}
class Product_OrderItem extends OrderItem {
protected $_productID;
protected $_productVersion;
static $db = array(
'ProductVersion' => 'Int'
);
static $has_one = array(
'Product' => 'Product'
);
}
?>
******************************************************
ProductGroup.php
<?php
/**
* Product Group is a 'holder' for Products within the CMS
* It contains functions for versioning child products
*
* @package ecommerce
*/
class ProductGroup extends Page {
public static $db = array(
'ChildGroupsPermission' => "Enum('Show Only Featured Products,Show All Products')"
);
public static $has_one = array();
public static $has_many = array();
public static $many_many = array();
public static $belongs_many_many = array(
'Products' => 'Product'
);
public static $defaults = array();
public static $casting = array();
static $default_child = 'Product';
static $add_action = 'a Product Group Page';
static $icon = 'cms/images/treeicons/folder';
static $include_child_groups = true;
static $page_length = 12;
static $must_have_price = false;
//TODO: allow grouping multiple sort fields under one 'sort option', and allow choosing direction of each
static $sort_options = array(
//'Title' => 'Web Design',
//'Price' => 'Logo/Branding',
//'NumberSold' => 'Testimonials'
//'Featured' => 'Featured',
//'Weight' => 'Weight'
'DateAdded' => 'Latest'
);
static $featured_products_permissions = array(
'Show Only Featured Products',
'Show All Products'
);
static $non_featured_products_permissions = array(
'Show All Products'
);
function set_page_length($length){
self::$page_length = $length;
}
function set_must_have_price($must = true){
self::$must_have_price = $must;
}
function set_sort_options(array $options){
self::$sort_options = $options;
}
function get_sort_options(){
return self::$sort_options;
}
function getCMSFields() {
$fields = parent::getCMSFields();
if(self::$include_child_groups === 'custom'){
$fields->addFieldToTab(
'Root.Content',
new Tab(
'Child Groups',
new HeaderField('How should products be presented in the child groups?'),
new DropdownField(
'ChildGroupsPermission',
'Permission',
$this->dbObject('ChildGroupsPermission')->enumValues(),
'',
null,
'Don\'t Show Any Products'
)
)
);
}
return $fields;
}
/**
* Returns the shopping cart.
* @todo Does HTTP::set_cache_age() still need to be set here?
*
* @return Order
*/
function Cart() {
HTTP::set_cache_age(0);
return ShoppingCart::current_order();
}
/**
* Retrieve a set of products, based on the given parameters. Checks get query for sorting and pagination.
*
* @param string $extraFilter Additional SQL filters to apply to the Product retrieval
* @param array $permissions
* @return DataObjectSet
*/
function ProductsShowable($extraFilter = '', $permissions = array("Show All Products")) { //TODO: re-introduce custom permissions, if wanted
$filter = ""; //
$join = "";
if($extraFilter) $filter.= " AND $extraFilter";
if(self::$must_have_price) $filter .= " AND Price > 0";
$limit = (isset($_GET['start']) && (int)$_GET['start'] > 0) ? (int)$_GET['start'].",".self::$page_length : "0,".self::$page_length;
$sort = (isset($_GET['sortby'])) ? Convert::raw2sql($_GET['sortby']) : "DateAdded DESC,Title";
//hard coded sort configuration //TODO: make these custom
if($sort == "DateAdded") $sort .= " DESC";
$groupids = array($this->ID);
if(self::$include_child_groups && $childgroups = $this->ChildGroups(true))
$groupids = array_merge($groupids,$childgroups->map('ID','ID'));
$groupidsimpl = implode(',',$groupids);
$join = $this->getManyManyJoin('Products','Product');
$multicatfilter = $this->getManyManyFilter('Products','Product');
//TODO: get products that appear in child groups (make this optional)
$products = DataObject::get('Product',"(ParentID IN ($groupidsimpl) OR $multicatfilter) $filter",$sort,$join,$limit);
$allproducts = DataObject::get('Product',"ParentID IN ($groupidsimpl) $filter","",$join);
if($allproducts) $products->TotalCount = $allproducts->Count(); //add total count to returned data for 'showing x to y of z products'
if($products) $products->removeDuplicates();
return $products;
}
/**
* Return children ProductGroup pages of this group.
* @return DataObjectSet
*/
function ChildGroups($recursive = false) {
if($recursive){
if($children = DataObject::get('ProductGroup', "`ParentID` = '$this->ID'")){
$output = unserialize(serialize($children));
foreach($children as $group){
$output->merge($group->ChildGroups($recursive));
}
return $output;
}
return null;
}else{
return DataObject::get('ProductGroup', "`ParentID` = '$this->ID'");
}
}
/**
* Recursively generate a product menu.
* @return DataObjectSet
*/
function GroupsMenu() {
if($parent = $this->Parent()) {
return $parent instanceof ProductGroup ? $parent->GroupsMenu() : $this->ChildGroups();
} else {
return $this->ChildGroups();
}
}
/**
* Automatically creates some ProductGroup pages in
* the CMS when the database builds if there hasn't
* been any set up yet.
*/
function requireDefaultRecords() {
parent::requireDefaultRecords();
if(!DataObject::get_one('ProductGroup')) {
$page1 = new ProductGroup();
$page1->Title = 'Products';
$page1->Content = "
<p>This is the top level products page, it uses the <em>product group</em> page type, and it allows you to show your products checked as 'featured' on it. It also allows you to nest <em>product group</em> pages inside it.</p>
<p>For example, you have a product group called 'DVDs', and inside you have more product groups like 'sci-fi', 'horrors' or 'action'.</p>
<p>In this example we have setup a main product group (this page), with a nested product group containing 2 example products.</p>
";
$page1->URLSegment = 'products';
$page1->writeToStage('Stage');
$page1->publish('Stage', 'Live');
DB::alteration_message('Product group page \'Products\' created', 'created');
$page2 = new ProductGroup();
$page2->Title = 'Example product group';
$page2->Content = '<p>This is a nested <em>product group</em> within the main <em>product group</em> page. You can add a paragraph here to describe what this product group is about, and what sort of products you can expect to find in it.</p>';
$page2->URLSegment = 'example-product-group';
$page2->ParentID = $page1->ID;
$page2->writeToStage('Stage');
$page2->publish('Stage', 'Live');
DB::alteration_message('Product group page \'Example product group\' created', 'created');
}
}
}
class ProductGroup_Controller extends Page_Controller {
function init() {
parent::init();
Requirements::themedCSS('ProductGroup');
Requirements::themedCSS('Cart');
}
/**
* Return the products for this group.
*/
public function Products(){
return $this->ProductsShowable();
}
/**
* Return products that are featured, that is products that have "FeaturedProduct = 1"
*/
function FeaturedProducts() {
return $this->ProductsShowable("`FeaturedProduct` = 1");
}
/**
* Return products that are not featured, that is products that have "FeaturedProduct = 0"
*/
function NonFeaturedProducts() {
return $this->ProductsShowable("`FeaturedProduct` = 0");
}
/**
* Provides a dataset of links for sorting products.
*/
}
?>