Advertisement
Guest User

Untitled

a guest
Nov 20th, 2014
160
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.14 KB | None | 0 0
  1. <?php
  2. /**
  3. * Represents a Product, which is a type of a {@link Page}. Products are managed in a seperate
  4. * admin area {@link ShopAdmin}. A product can have {@link Variation}s, in fact if a Product
  5. * has attributes (e.g Size, Color) then it must have Variations. Products are Versioned so that
  6. * when a Product is added to an Order, then subsequently changed, the Order can get the correct
  7. * details about the Product.
  8. */
  9. class Product extends Page {
  10.  
  11. /**
  12. * Flag for denoting if this is the first time this Product is being written.
  13. *
  14. * @var Boolean
  15. */
  16. protected $firstWrite = false;
  17.  
  18. /**
  19. * DB fields for Product.
  20. *
  21. * @var Array
  22. */
  23. public static $db = array(
  24. 'Price' => 'Decimal(19,8)',
  25. 'Currency' => 'Varchar(3)'
  26. );
  27. /**
  28. * Actual price in base currency, can decorate to apply discounts etc.
  29. *
  30. * @return Price
  31. */
  32. public function Amount() {
  33.  
  34. // TODO: Multi currency
  35. $shopConfig = ShopConfig::current_shop_config();
  36.  
  37. $amount = Price::create();
  38. $amount->setAmount($this->Price);
  39. $amount->setCurrency($shopConfig->BaseCurrency);
  40. $amount->setSymbol($shopConfig->BaseCurrencySymbol);
  41.  
  42. //Transform amount for applying discounts etc.
  43. $this->extend('updateAmount', $amount);
  44.  
  45. return $amount;
  46. }
  47.  
  48. /**
  49. * Display price, can decorate for multiple currency etc.
  50. *
  51. * @return Price
  52. */
  53. public function Price() {
  54.  
  55. $amount = $this->Amount();
  56.  
  57. //Transform price here for display in different currencies etc.
  58. $this->extend('updatePrice', $amount);
  59.  
  60. return $amount;
  61. }
  62.  
  63. /**
  64. * Has many relations for Product.
  65. *
  66. * @var Array
  67. */
  68. private static $has_many = array(
  69. 'Images' => 'ProductImage',
  70. 'Attributes' => 'Attribute',
  71. 'Options' => 'Option',
  72. 'Variations' => 'Variation',
  73. 'ProductDropDowns' => 'ProductDropDowns',
  74. 'Testimonials' => 'Testimonials'
  75. );
  76.  
  77. private static $many_many = array(
  78. 'RelatedProducts' => 'Product'
  79. );
  80.  
  81. /**
  82. * Defaults for Product
  83. *
  84. * @var Array
  85. */
  86. private static $defaults = array(
  87. 'ParentID' => -1
  88. );
  89.  
  90. /**
  91. * Summary fields for displaying Products in the CMS
  92. *
  93. * @var Array
  94. */
  95. private static $summary_fields = array(
  96. 'FirstImage' => 'Image',
  97. 'Amount.Nice' => 'Price',
  98. 'Title' => 'Title'
  99. );
  100.  
  101. private static $searchable_fields = array(
  102. 'Title' => array(
  103. 'field' => 'TextField',
  104. 'filter' => 'PartialMatchFilter',
  105. 'title' => 'Name'
  106. )
  107. );
  108.  
  109. /**
  110. * Set firstWrite flag if this is the first time this Product is written.
  111. *
  112. * @see SiteTree::onBeforeWrite()
  113. * @see Product::onAfterWrite()
  114. */
  115. public function onBeforeWrite() {
  116. parent::onBeforeWrite();
  117. if (!$this->ID) $this->firstWrite = true;
  118.  
  119. //Save in base currency
  120. $shopConfig = ShopConfig::current_shop_config();
  121. $this->Currency = $shopConfig->BaseCurrency;
  122. }
  123.  
  124. /**
  125. * Unpublish products if they get deleted, such as in product admin area
  126. *
  127. * @see SiteTree::onAfterDelete()
  128. */
  129. public function onAfterDelete() {
  130. parent::onAfterDelete();
  131.  
  132. if ($this->isPublished()) {
  133. $this->doUnpublish();
  134. }
  135. }
  136.  
  137. /**
  138. * Set some CMS fields for managing Products
  139. *
  140. * @see Page::getCMSFields()
  141. * @return FieldList
  142. */
  143. public function getCMSFields() {
  144.  
  145. $shopConfig = ShopConfig::current_shop_config();
  146. $fields = parent::getCMSFields();
  147.  
  148.  
  149. //Gallery
  150. $gridFieldConfig = GridFieldConfig::create()->addComponents(
  151. new GridFieldToolbarHeader(),
  152. new GridFieldAddNewButton('toolbar-header-right'),
  153. new GridFieldSortableHeader(),
  154. new GridFieldDataColumns(),
  155. new GridFieldPaginator(10),
  156. new GridFieldEditButton(),
  157. new GridFieldDeleteAction(),
  158. new GridFieldDetailForm()
  159. );
  160.  
  161. $manager = new GridField("Gallery", "Images list:", $this->Images(), $gridFieldConfig);
  162. $fields->addFieldToTab("Root.Gallery", new HeaderField(
  163. 'GalleryHeading',
  164. 'Add images for this product, the first image will be used as a thumbnail',
  165. 3
  166. ));
  167. $fields->addFieldToTab("Root.Gallery", $manager);
  168.  
  169. //Product fields
  170. $fields->addFieldToTab('Root.Main', new PriceField('Price'), 'Content');
  171.  
  172. //Related Products
  173. $gridFieldComplex = GridFieldConfig::create()->addComponents(
  174. new GridFieldToolbarHeader(),
  175. new GridFieldAddNewButton('toolbar-header-right'),
  176. new GridFieldSortableHeader(),
  177. new GridFieldDataColumns(),
  178. new GridFieldManyRelationHandler(),
  179. new GridFieldPaginator(10),
  180. new GridFieldEditButton(),
  181. new GridFieldDeleteAction(),
  182. new GridFieldDetailForm()
  183. );
  184.  
  185. $tablefield = new GridField(
  186. 'RelatedProducts',
  187. 'Related Products:',
  188. $this->RelatedProducts(),
  189. $gridFieldComplex
  190. );
  191. $fields->addFieldToTab('Root.RelatedProducts', $tablefield);
  192.  
  193. //Testimonials
  194. $testimonialTable = new GridField(
  195. 'Testimonials',
  196. 'Testimonials:',
  197. $this->Testimonials(),
  198. $gridFieldConfig
  199. );
  200. $fields->addFieldToTab('Root.Testimonials', $testimonialTable);
  201.  
  202. //Expanding content area
  203. $contentTable = new GridField(
  204. 'ProductDropDowns',
  205. 'Expanding Content:',
  206. $this->ProductDropDowns(),
  207. $gridFieldConfig
  208. );
  209. $fields->addFieldToTab('Root.ExpandingContent', $contentTable);
  210.  
  211. //Replace URL Segment field
  212. if ($this->ParentID == -1) {
  213. $urlsegment = new SiteTreeURLSegmentField("URLSegment", 'URLSegment');
  214. $baseLink = Controller::join_links(Director::absoluteBaseURL(), 'product/');
  215. $url = (strlen($baseLink) > 36) ? "..." .substr($baseLink, -32) : $baseLink;
  216. $urlsegment->setURLPrefix($url);
  217. $fields->replaceField('URLSegment', $urlsegment);
  218. }
  219.  
  220. if ($this->isInDB()) {
  221.  
  222. //Product attributes
  223. $listField = new GridField(
  224. 'Attributes',
  225. 'Attributes',
  226. $this->Attributes(),
  227. GridFieldConfig_BasicSortable::create()
  228. );
  229. $fields->addFieldToTab('Root.Attributes', $listField);
  230.  
  231. //Product variations
  232. $attributes = $this->Attributes();
  233. if ($attributes && $attributes->exists()) {
  234.  
  235. //Remove the stock level field if there are variations, each variation has a stock field
  236. $fields->removeByName('Stock');
  237.  
  238. $variationFieldList = array();
  239. foreach ($attributes as $attribute) {
  240. $variationFieldList['AttributeValue_'.$attribute->ID] = $attribute->Title;
  241. }
  242. $variationFieldList = array_merge($variationFieldList, singleton('Variation')->summaryFields());
  243.  
  244. $config = GridFieldConfig_HasManyRelationEditor::create();
  245. $dataColumns = $config->getComponentByType('GridFieldDataColumns');
  246. $dataColumns->setDisplayFields($variationFieldList);
  247.  
  248. $listField = new GridField(
  249. 'Variations',
  250. 'Variations',
  251. $this->Variations(),
  252. $config
  253. );
  254. $fields->addFieldToTab('Root.Variations', $listField);
  255. }
  256. }
  257.  
  258. //Ability to edit fields added to CMS here
  259. $this->extend('updateProductCMSFields', $fields);
  260.  
  261. if ($warning = ShopConfig::base_currency_warning()) {
  262. $fields->addFieldToTab('Root.Main', new LiteralField('BaseCurrencyWarning',
  263. '<p class="message warning">'.$warning.'</p>'
  264. ), 'Title');
  265. }
  266.  
  267. return $fields;
  268. }
  269.  
  270. /**
  271. * Get the URL for this Product, products that are not part of the SiteTree are
  272. * displayed by the {@link Product_Controller}.
  273. *
  274. * @see SiteTree::Link()
  275. * @see Product_Controller::show()
  276. * @return String
  277. */
  278. public function Link($action = null) {
  279.  
  280. if ($this->ParentID > -1) {
  281. return parent::Link($action);
  282. }
  283. return Controller::join_links(Director::baseURL() . 'product/', $this->RelativeLink($action));
  284. }
  285.  
  286. /**
  287. * A product is required to be added to a cart with a variation if it has attributes.
  288. * A product with attributes needs to have some enabled {@link Variation}s
  289. *
  290. * @return Boolean
  291. */
  292. public function requiresVariation() {
  293. $attributes = $this->Attributes();
  294.  
  295. $this->extend('updaterequiresVariation', $attributes);
  296.  
  297. return $attributes && $attributes->exists();
  298. }
  299.  
  300. /**
  301. * Get options for an Attribute of this Product.
  302. *
  303. * @param Int $attributeID
  304. * @return ArrayList
  305. */
  306. public function getOptionsForAttribute($attributeID) {
  307.  
  308. $options = new ArrayList();
  309. $variations = $this->Variations();
  310.  
  311. if ($variations && $variations->exists()) foreach ($variations as $variation) {
  312.  
  313. if ($variation->isEnabled()) {
  314. $option = $variation->getOptionForAttribute($attributeID);
  315. if ($option) $options->push($option);
  316. }
  317. }
  318. $options = $options->sort('SortOrder');
  319. return $options;
  320. }
  321.  
  322. /**
  323. * Validate the Product before it is saved in {@link ShopAdmin}.
  324. *
  325. * @see DataObject::validate()
  326. * @return ValidationResult
  327. */
  328. public function validate() {
  329.  
  330. $result = new ValidationResult();
  331.  
  332. //If this is being published, check that enabled variations exist if they are required
  333. $request = Controller::curr()->getRequest();
  334. $publishing = ($request && $request->getVar('action_publish')) ? true : false;
  335.  
  336. if ($publishing && $this->requiresVariation()) {
  337.  
  338. $variations = $this->Variations();
  339.  
  340. if (!in_array('Enabled', $variations->map('ID', 'Status')->toArray())) {
  341. $result->error(
  342. 'Cannot publish product when no variations are enabled. Please enable some product variations and try again.',
  343. 'VariationsDisabledError'
  344. );
  345. }
  346. }
  347. return $result;
  348. }
  349.  
  350. }
  351.  
  352. /**
  353. * Displays a product, add to cart form, gets options and variation price for a {@link Product}
  354. * via AJAX.
  355. *
  356. * @author Frank Mullenger <frankmullenger@gmail.com>
  357. * @copyright Copyright (c) 2011, Frank Mullenger
  358. * @package swipestripe
  359. * @subpackage product
  360. */
  361. class Product_Controller extends Page_Controller {
  362.  
  363. /**
  364. * Allowed actions for this controller
  365. *
  366. * @var Array
  367. */
  368. private static $allowed_actions = array(
  369. 'ProductForm'
  370. );
  371.  
  372. /**
  373. * Include some CSS and set the dataRecord to the current Product that is being viewed.
  374. *
  375. * @see Page_Controller::init()
  376. */
  377. public function init() {
  378. parent::init();
  379.  
  380. Requirements::css('swipestripe/css/Shop.css');
  381.  
  382. //Get current product page for products that are not part of the site tree
  383. //and do not have a ParentID set, they are accessed via this controller using
  384. //Director rules
  385. if ($this->dataRecord->ID == -1) {
  386.  
  387. $params = $this->getURLParams();
  388.  
  389. if ($urlSegment = Convert::raw2sql($params['ID'])) {
  390.  
  391. $product = Product::get()
  392. ->where("\"URLSegment\" = '$urlSegment'")
  393. ->limit(1)
  394. ->first();
  395.  
  396. if ($product && $product->exists()) {
  397. $this->dataRecord = $product;
  398. $this->failover = $this->dataRecord;
  399.  
  400. $this->customise(array(
  401. 'Product' => $this->data()
  402. ));
  403. }
  404. }
  405. }
  406.  
  407. $this->extend('onInit');
  408. }
  409.  
  410. /**
  411. * Legacy function allowing access to product data via $Product variable in templates
  412. */
  413. public function Product() {
  414. return $this->data();
  415. }
  416.  
  417. public function ProductForm($quantity = null, $redirectURL = null) {
  418.  
  419. return ProductForm::create(
  420. $this,
  421. 'ProductForm',
  422. $quantity,
  423. $redirectURL
  424. )->disableSecurityToken();
  425. }
  426. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement