These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * Product Group is a 'holder' for Products within the CMS |
||
5 | * It contains functions for versioning child products. |
||
6 | * |
||
7 | * The way the products are selected: |
||
8 | * |
||
9 | * Controller calls: |
||
10 | * ProductGroup::ProductsShowable($extraFilter = "") |
||
11 | * |
||
12 | * ProductsShowable runs currentInitialProducts. This selects ALL the applicable products |
||
13 | * but it does NOT PAGINATE (limit) or SORT them. |
||
14 | * After that, it calls currentFinalProducts, this sorts the products and notes the total |
||
15 | * count of products (removing ones that can not be shown for one reason or another) |
||
16 | * |
||
17 | * Pagination is done in the controller. |
||
18 | * |
||
19 | * For each product page, there is a default: |
||
20 | * - filter |
||
21 | * - sort |
||
22 | * - number of levels to show (e.g. children, grand-children, etc...) |
||
23 | * and these settings can be changed in the CMS, depending on what the |
||
24 | * developer makes available to the content editor. |
||
25 | * |
||
26 | * In extending the ProductGroup class, it is recommended |
||
27 | * that you override the following methods (as required ONLY!): |
||
28 | * - getBuyableClassName |
||
29 | * - getGroupFilter |
||
30 | * - getStandardFilter |
||
31 | * - getGroupJoin |
||
32 | * - currentSortSQL |
||
33 | * - limitCurrentFinalProducts |
||
34 | * - removeExcludedProductsAndSaveIncludedProducts |
||
35 | * |
||
36 | * To filter products, you have three options: |
||
37 | * |
||
38 | * (1) getGroupFilter |
||
39 | * - the standard product groups from which the products are selected |
||
40 | * - if you extend Product Group this is the one you most likely want to change |
||
41 | * - for example, rather than children, you set it to "yellow" products |
||
42 | * - goes hand in hand with changes to showProductLevels / LevelOfProductsToShow |
||
43 | * - works out the group filter based on the LevelOfProductsToShow value |
||
44 | * - it also considers the other group many-many relationship |
||
45 | * - this filter ALWAYS returns something: 1 = 1 if nothing else. |
||
46 | * |
||
47 | * (2) getStandardFilter |
||
48 | * - these are the standard (user selectable) filters |
||
49 | * - available options set via config |
||
50 | * - the standard filter is updated by controller |
||
51 | * - options can show above / below product lists to let user select alternative filter. |
||
52 | * |
||
53 | * (3) the extraWhere in ProductsShowable |
||
54 | * - provided by the controller for specific ('on the fly') sub-sets |
||
55 | * - this is for example for search results |
||
56 | * - set in ProductShowable($extraWhere) |
||
57 | * |
||
58 | * |
||
59 | * Caching |
||
60 | * ================== |
||
61 | * |
||
62 | * There are two type of caching available: |
||
63 | * |
||
64 | * (1) caching of Product SQL queries |
||
65 | * - turned on and off by variable: ProductGroup->allowCaching |
||
66 | * - this is not a static so that you can create different settings for ProductGroup extensions. |
||
67 | * (2) caching of product lists |
||
68 | * - see Product_Controller::ProductGroupListAreCacheable |
||
69 | * |
||
70 | * You can also ajaxify the product list, although this has nothing to do with |
||
71 | * caching, it is related to it. |
||
72 | * |
||
73 | * |
||
74 | * @authors: Nicolaas [at] Sunny Side Up .co.nz |
||
75 | * @package: ecommerce |
||
76 | * @sub-package: Pages |
||
77 | * @inspiration: Silverstripe Ltd, Jeremy |
||
78 | **/ |
||
79 | class ProductGroup extends Page |
||
80 | { |
||
81 | /** |
||
82 | * standard SS variable. |
||
83 | * |
||
84 | * @static Array |
||
85 | */ |
||
86 | private static $db = array( |
||
87 | 'NumberOfProductsPerPage' => 'Int', |
||
88 | 'LevelOfProductsToShow' => 'Int', |
||
89 | 'DefaultSortOrder' => 'Varchar(20)', |
||
90 | 'DefaultFilter' => 'Varchar(20)', |
||
91 | 'DisplayStyle' => 'Varchar(20)', |
||
92 | ); |
||
93 | |||
94 | /** |
||
95 | * standard SS variable. |
||
96 | * |
||
97 | * @static Array |
||
98 | */ |
||
99 | private static $has_one = array( |
||
100 | 'Image' => 'Product_Image', |
||
101 | ); |
||
102 | |||
103 | /** |
||
104 | * standard SS variable. |
||
105 | * |
||
106 | * @static Array |
||
107 | */ |
||
108 | private static $belongs_many_many = array( |
||
109 | 'AlsoShowProducts' => 'Product', |
||
110 | ); |
||
111 | |||
112 | /** |
||
113 | * standard SS variable. |
||
114 | * |
||
115 | * @static Array |
||
116 | */ |
||
117 | private static $defaults = array( |
||
118 | 'DefaultSortOrder' => 'default', |
||
119 | 'DefaultFilter' => 'default', |
||
120 | 'DisplayStyle' => 'default', |
||
121 | 'LevelOfProductsToShow' => 99, |
||
122 | ); |
||
123 | |||
124 | /** |
||
125 | * standard SS variable. |
||
126 | * |
||
127 | * @static Array |
||
128 | */ |
||
129 | private static $indexes = array( |
||
130 | 'LevelOfProductsToShow' => true, |
||
131 | 'DefaultSortOrder' => true, |
||
132 | 'DefaultFilter' => true, |
||
133 | 'DisplayStyle' => true, |
||
134 | ); |
||
135 | |||
136 | private static $summary_fields = array( |
||
137 | 'Image.CMSThumbnail' => 'Image', |
||
138 | 'Title' => 'Category', |
||
139 | 'NumberOfProducts' => 'Direct Product Count' |
||
140 | ); |
||
141 | |||
142 | private static $casting = array( |
||
143 | 'NumberOfProducts' => 'Int' |
||
144 | ); |
||
145 | |||
146 | /** |
||
147 | * standard SS variable. |
||
148 | * |
||
149 | * @static String |
||
150 | */ |
||
151 | private static $default_child = 'Product'; |
||
152 | |||
153 | /** |
||
154 | * standard SS variable. |
||
155 | * |
||
156 | * @static String | Array |
||
157 | */ |
||
158 | private static $icon = 'ecommerce/images/icons/productgroup'; |
||
159 | |||
160 | /** |
||
161 | * Standard SS variable. |
||
162 | */ |
||
163 | private static $singular_name = 'Product Category'; |
||
164 | public function i18n_singular_name() |
||
165 | { |
||
166 | return _t('ProductGroup.SINGULARNAME', 'Product Category'); |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Standard SS variable. |
||
171 | */ |
||
172 | private static $plural_name = 'Product Categories'; |
||
173 | public function i18n_plural_name() |
||
174 | { |
||
175 | return _t('ProductGroup.PLURALNAME', 'Product Categories'); |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * Standard SS variable. |
||
180 | * |
||
181 | * @var string |
||
182 | */ |
||
183 | private static $description = 'A page the shows a bunch of products, based on your selection. By default it shows products linked to it (children)'; |
||
184 | |||
185 | public function canCreate($member = null) |
||
0 ignored issues
–
show
|
|||
186 | { |
||
187 | if (! $member) { |
||
188 | $member = Member::currentUser(); |
||
189 | } |
||
190 | $extended = $this->extendedCan(__FUNCTION__, $member); |
||
191 | if ($extended !== null) { |
||
192 | return $extended; |
||
193 | } |
||
194 | if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) { |
||
195 | return true; |
||
196 | } |
||
197 | |||
198 | return parent::canEdit($member); |
||
0 ignored issues
–
show
It seems like you call parent on a different method (
canEdit() instead of canCreate() ). Are you sure this is correct? If so, you might want to change this to $this->canEdit() .
This check looks for a call to a parent method whose name is different than the method from which it is called. Consider the following code: class Daddy
{
protected function getFirstName()
{
return "Eidur";
}
protected function getSurName()
{
return "Gudjohnsen";
}
}
class Son
{
public function getFirstName()
{
return parent::getSurname();
}
}
The
Loading history...
|
|||
199 | } |
||
200 | |||
201 | /** |
||
202 | * Shop Admins can edit. |
||
203 | * |
||
204 | * @param Member $member |
||
0 ignored issues
–
show
Should the type for parameter
$member not be Member|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
205 | * |
||
206 | * @return bool |
||
207 | */ |
||
208 | public function canEdit($member = null) |
||
209 | { |
||
210 | if (! $member) { |
||
211 | $member = Member::currentUser(); |
||
212 | } |
||
213 | $extended = $this->extendedCan(__FUNCTION__, $member); |
||
214 | if ($extended !== null) { |
||
215 | return $extended; |
||
216 | } |
||
217 | if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) { |
||
218 | return true; |
||
219 | } |
||
220 | |||
221 | return parent::canEdit($member); |
||
222 | } |
||
223 | |||
224 | /** |
||
225 | * Standard SS method. |
||
226 | * |
||
227 | * @param Member $member |
||
0 ignored issues
–
show
Should the type for parameter
$member not be Member|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
228 | * |
||
229 | * @return bool |
||
230 | */ |
||
231 | public function canDelete($member = null) |
||
232 | { |
||
233 | if (is_a(Controller::curr(), Object::getCustomClass('ProductsAndGroupsModelAdmin'))) { |
||
234 | return false; |
||
235 | } |
||
236 | if (! $member) { |
||
237 | $member = Member::currentUser(); |
||
238 | } |
||
239 | $extended = $this->extendedCan(__FUNCTION__, $member); |
||
240 | if ($extended !== null) { |
||
241 | return $extended; |
||
242 | } |
||
243 | if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) { |
||
244 | return true; |
||
245 | } |
||
246 | |||
247 | return parent::canEdit($member); |
||
0 ignored issues
–
show
It seems like you call parent on a different method (
canEdit() instead of canDelete() ). Are you sure this is correct? If so, you might want to change this to $this->canEdit() .
This check looks for a call to a parent method whose name is different than the method from which it is called. Consider the following code: class Daddy
{
protected function getFirstName()
{
return "Eidur";
}
protected function getSurName()
{
return "Gudjohnsen";
}
}
class Son
{
public function getFirstName()
{
return parent::getSurname();
}
}
The
Loading history...
|
|||
248 | } |
||
249 | |||
250 | /** |
||
251 | * Standard SS method. |
||
252 | * |
||
253 | * @param Member $member |
||
0 ignored issues
–
show
Should the type for parameter
$member not be Member|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types.
Loading history...
|
|||
254 | * |
||
255 | * @return bool |
||
256 | */ |
||
257 | public function canPublish($member = null) |
||
258 | { |
||
259 | if (Permission::checkMember($member, Config::inst()->get('EcommerceRole', 'admin_permission_code'))) { |
||
260 | return true; |
||
261 | } |
||
262 | |||
263 | return parent::canEdit($member); |
||
0 ignored issues
–
show
It seems like you call parent on a different method (
canEdit() instead of canPublish() ). Are you sure this is correct? If so, you might want to change this to $this->canEdit() .
This check looks for a call to a parent method whose name is different than the method from which it is called. Consider the following code: class Daddy
{
protected function getFirstName()
{
return "Eidur";
}
protected function getSurName()
{
return "Gudjohnsen";
}
}
class Son
{
public function getFirstName()
{
return parent::getSurname();
}
}
The
Loading history...
|
|||
264 | } |
||
265 | |||
266 | /** |
||
267 | * list of sort / filter / display variables. |
||
268 | * |
||
269 | * @var array |
||
270 | */ |
||
271 | protected $sortFilterDisplayNames = array( |
||
272 | 'SORT' => array( |
||
273 | 'value' => 'default', |
||
274 | 'configName' => 'sort_options', |
||
275 | 'sessionName' => 'session_name_for_sort_preference', |
||
276 | 'getVariable' => 'sort', |
||
277 | 'dbFieldName' => 'DefaultSortOrder', |
||
278 | 'translationCode' => 'SORT_BY', |
||
279 | ), |
||
280 | 'FILTER' => array( |
||
281 | 'value' => 'default', |
||
282 | 'configName' => 'filter_options', |
||
283 | 'sessionName' => 'session_name_for_filter_preference', |
||
284 | 'getVariable' => 'filter', |
||
285 | 'dbFieldName' => 'DefaultFilter', |
||
286 | 'translationCode' => 'FILTER_FOR', |
||
287 | ), |
||
288 | 'DISPLAY' => array( |
||
289 | 'value' => 'default', |
||
290 | 'configName' => 'display_styles', |
||
291 | 'sessionName' => 'session_name_for_display_style_preference', |
||
292 | 'getVariable' => 'display', |
||
293 | 'dbFieldName' => 'DisplayStyle', |
||
294 | 'translationCode' => 'DISPLAY_STYLE', |
||
295 | ), |
||
296 | ); |
||
297 | |||
298 | /** |
||
299 | * @var array |
||
300 | * List of options to show products. |
||
301 | * With it, we provide a bunch of methods to access and edit the options. |
||
302 | * NOTE: we can not have an option that has a zero key ( 0 => "none"), as this does not work |
||
303 | * (as it is equal to not completed yet - not yet entered in the Database). |
||
304 | */ |
||
305 | protected $showProductLevels = array( |
||
306 | 99 => 'All Child Products (default)', |
||
307 | -2 => 'None', |
||
308 | -1 => 'All products', |
||
309 | 1 => 'Direct Child Products', |
||
310 | 2 => 'Direct Child Products + Grand Child Products', |
||
311 | 3 => 'Direct Child Products + Grand Child Products + Great Grand Child Products', |
||
312 | 4 => 'Direct Child Products + Grand Child Products + Great Grand Child Products + Great Great Grand Child Products', |
||
313 | ); |
||
314 | |||
315 | /** |
||
316 | * variable to speed up methods in this class. |
||
317 | * |
||
318 | * @var array |
||
319 | */ |
||
320 | protected $configOptionsCache = array(); |
||
321 | |||
322 | /** |
||
323 | * cache variable for default preference key. |
||
324 | * |
||
325 | * @var array |
||
326 | */ |
||
327 | protected $myUserPreferencesDefaultCache = array(); |
||
328 | |||
329 | /** |
||
330 | * count before limit. |
||
331 | * |
||
332 | * @var int |
||
333 | */ |
||
334 | protected $rawCount = 0; |
||
335 | |||
336 | /** |
||
337 | * count after limit. |
||
338 | * |
||
339 | * @var int |
||
340 | */ |
||
341 | protected $totalCount = 0; |
||
342 | |||
343 | /** |
||
344 | * Can product list (and related) be cached at all? |
||
345 | * Set this to FALSE if the product details can be changed |
||
346 | * for an individual user. |
||
347 | * |
||
348 | * @var bool |
||
349 | */ |
||
350 | protected $allowCaching = true; |
||
351 | |||
352 | /** |
||
353 | * return the options for one type. |
||
354 | * This method solely exists to speed up processing. |
||
355 | * |
||
356 | * @param string $type - options are FILTER | SORT | DISPLAY |
||
357 | * |
||
358 | * @return array |
||
359 | */ |
||
360 | protected function getConfigOptions($type) |
||
361 | { |
||
362 | if (!isset($this->configOptionsCache[$type])) { |
||
363 | $configName = $this->sortFilterDisplayNames[$type]['configName']; |
||
364 | $this->configOptionsCache[$type] = EcommerceConfig::get($this->ClassName, $configName); |
||
365 | } |
||
366 | |||
367 | return $this->configOptionsCache[$type]; |
||
368 | } |
||
369 | |||
370 | /** |
||
371 | * returns the full sortFilterDisplayNames set, a subset, or one value |
||
372 | * by either type (e.g. FILER) or variable (e.g dbFieldName) |
||
373 | * or both. |
||
374 | * |
||
375 | * @param string $typeOfVariableName FILTER | SORT | DISPLAY or sessionName, getVariable, etc... |
||
0 ignored issues
–
show
There is no parameter named
$typeOfVariableName . Did you maybe mean $variable ?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit. Consider the following example. The parameter /**
* @param array $germany
* @param array $ireland
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was changed, but the annotation was not.
Loading history...
|
|||
376 | * @param string $variable: sessionName, getVariable, etc... |
||
0 ignored issues
–
show
There is no parameter named
$variable: . Did you maybe mean $variable ?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit. Consider the following example. The parameter /**
* @param array $germany
* @param array $ireland
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was changed, but the annotation was not.
Loading history...
|
|||
377 | * |
||
378 | * @return array | String |
||
379 | */ |
||
380 | protected function getSortFilterDisplayNames($typeOrVariable = '', $variable = '') |
||
381 | { |
||
382 | //return a string ... |
||
383 | if ($variable) { |
||
384 | return $this->sortFilterDisplayNames[$typeOrVariable][$variable]; |
||
385 | } |
||
386 | //return an array ... |
||
387 | $data = array(); |
||
388 | if (isset($this->sortFilterDisplayNames[$typeOrVariable])) { |
||
389 | $data = $this->sortFilterDisplayNames[$typeOrVariable]; |
||
390 | } elseif ($typeOrVariable) { |
||
391 | foreach ($this->sortFilterDisplayNames as $group) { |
||
392 | $data[] = $group[$typeOrVariable]; |
||
393 | } |
||
394 | } else { |
||
395 | $data = $this->sortFilterDisplayNames; |
||
396 | } |
||
397 | |||
398 | return $data; |
||
399 | } |
||
400 | |||
401 | /** |
||
402 | * sets a user preference. This is typically used by the controller |
||
403 | * to set filter and sort. |
||
404 | * |
||
405 | * @param string $type SORT | FILTER | DISPLAY |
||
406 | * @param string $value |
||
407 | */ |
||
408 | protected function setCurrentUserPreference($type, $value) |
||
409 | { |
||
410 | $this->sortFilterDisplayNames[$type]['value'] = $value; |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * Get a user preference. |
||
415 | * This value can be updated by the controller |
||
416 | * For example, the filter can be changed, based on a session value. |
||
417 | * |
||
418 | * @param string $type SORT | FILTER | DISPLAY |
||
419 | * |
||
420 | * @return string |
||
421 | */ |
||
422 | protected function getCurrentUserPreferences($type) |
||
423 | { |
||
424 | return $this->sortFilterDisplayNames[$type]['value']; |
||
425 | } |
||
426 | |||
427 | /********************* |
||
428 | * SETTINGS: Default Key |
||
429 | *********************/ |
||
430 | |||
431 | /** |
||
432 | * Checks for the most applicable user preferences for this page: |
||
433 | * 1. what is saved in Database for this page. |
||
434 | * 2. what the parent product group has saved in the database |
||
435 | * 3. what the standard default is. |
||
436 | * |
||
437 | * @param string $type - FILTER | SORT | DISPLAY |
||
438 | * |
||
439 | * @return string - returns the key |
||
440 | */ |
||
441 | protected function getMyUserPreferencesDefault($type) |
||
442 | { |
||
443 | if (!isset($this->myUserPreferencesDefaultCache[$type]) || !$this->myUserPreferencesDefaultCache[$type]) { |
||
444 | $options = $this->getConfigOptions($type); |
||
445 | $dbVariableName = $this->sortFilterDisplayNames[$type]['dbFieldName']; |
||
446 | $defaultOption = ''; |
||
447 | if ($defaultOption == 'inherit' && $parent = $this->ParentGroup()) { |
||
448 | $defaultOption = $parent->getMyUserPreferencesDefault($type); |
||
449 | } elseif ($this->$dbVariableName && array_key_exists($this->$dbVariableName, $options)) { |
||
450 | $defaultOption = $this->$dbVariableName; |
||
451 | } |
||
452 | if (!$defaultOption) { |
||
453 | if (isset($options['default'])) { |
||
454 | $defaultOption = 'default'; |
||
455 | } else { |
||
456 | user_error("It is recommended that you have a default (key) option for $type", E_USER_NOTICE); |
||
457 | $keys = array_keys($options); |
||
458 | $defaultOption = $keys[0]; |
||
459 | } |
||
460 | } |
||
461 | $this->myUserPreferencesDefaultCache[$type] = $defaultOption; |
||
462 | } |
||
463 | |||
464 | return $this->myUserPreferencesDefaultCache[$type]; |
||
465 | } |
||
466 | |||
467 | /********************* |
||
468 | * SETTINGS: Dropdowns |
||
469 | *********************/ |
||
470 | /** |
||
471 | * SORT: |
||
472 | * returns an array of Key => Title for sort options. |
||
473 | * |
||
474 | * FILTER: |
||
475 | * Returns options for the dropdown of filter options. |
||
476 | * |
||
477 | * DISPLAY: |
||
478 | * Returns the options for product display styles. |
||
479 | * In the configuration you can set which ones are available. |
||
480 | * If one is available then you must make sure that the corresponding template is available. |
||
481 | * For example, if the display style is |
||
482 | * MyTemplate => "All Details" |
||
483 | * Then you must make sure MyTemplate.ss exists. |
||
484 | * |
||
485 | * @param string $type - FILTER | SORT | DISPLAY |
||
486 | * |
||
487 | * @return array |
||
488 | */ |
||
489 | protected function getUserPreferencesOptionsForDropdown($type) |
||
490 | { |
||
491 | $options = $this->getConfigOptions($type); |
||
492 | $inheritTitle = _t('ProductGroup.INHERIT', 'Inherit'); |
||
493 | $array = array('inherit' => $inheritTitle); |
||
494 | if (is_array($options) && count($options)) { |
||
495 | foreach ($options as $key => $option) { |
||
496 | if (is_array($option)) { |
||
497 | $array[$key] = $option['Title']; |
||
498 | } else { |
||
499 | $array[$key] = $option; |
||
500 | } |
||
501 | } |
||
502 | } |
||
503 | |||
504 | return $array; |
||
505 | } |
||
506 | |||
507 | /********************* |
||
508 | * SETTINGS: SQL |
||
509 | *********************/ |
||
510 | |||
511 | /** |
||
512 | * SORT: |
||
513 | * Returns the sort sql for a particular sorting key. |
||
514 | * If no key is provided then the default key will be returned. |
||
515 | * |
||
516 | * @param string $key |
||
517 | * |
||
518 | * @return array (e.g. Array(MyField => "ASC", "MyOtherField" => "DESC") |
||
519 | * |
||
520 | * FILTER: |
||
521 | * Returns the sql associated with a filter option. |
||
522 | * |
||
523 | * @param string $type - FILTER | SORT | DISPLAY |
||
524 | * @param string $key - the options selected |
||
525 | * |
||
526 | * @return array | String (e.g. array("MyField" => 1, "MyOtherField" => 0)) OR STRING |
||
527 | */ |
||
528 | protected function getUserSettingsOptionSQL($type, $key = '') |
||
529 | { |
||
530 | $options = $this->getConfigOptions($type); |
||
531 | //if we cant find the current one, use the default |
||
532 | if (!$key || (!isset($options[$key]))) { |
||
533 | $key = $this->getMyUserPreferencesDefault($type); |
||
534 | } |
||
535 | if ($key) { |
||
536 | return $options[$key]['SQL']; |
||
537 | } else { |
||
538 | if ($type == 'FILTER') { |
||
539 | return array('Sort' => 'ASC'); |
||
540 | } elseif ($type == 'SORT') { |
||
541 | return array('ShowInSearch' => 1); |
||
542 | } |
||
543 | } |
||
544 | } |
||
545 | |||
546 | /********************* |
||
547 | * SETTINGS: Title |
||
548 | *********************/ |
||
549 | |||
550 | /** |
||
551 | * Returns the Title for a type key. |
||
552 | * If no key is provided then the default key is used. |
||
553 | * |
||
554 | * @param string $type - FILTER | SORT | DISPLAY |
||
555 | * @param string $key |
||
556 | * |
||
557 | * @return string |
||
558 | */ |
||
559 | public function getUserPreferencesTitle($type, $key = '') |
||
560 | { |
||
561 | $options = $this->getConfigOptions($type); |
||
562 | if (!$key || (!isset($options[$key]))) { |
||
563 | $key = $this->getMyUserPreferencesDefault($type); |
||
564 | } |
||
565 | if ($key && isset($options[$key]['Title'])) { |
||
566 | return $options[$key]['Title']; |
||
567 | } else { |
||
568 | return _t('ProductGroup.UNKNOWN', 'UNKNOWN USER SETTING'); |
||
569 | } |
||
570 | } |
||
571 | |||
572 | /********************* |
||
573 | * SETTINGS: products per page |
||
574 | *********************/ |
||
575 | |||
576 | /** |
||
577 | *@return int |
||
578 | **/ |
||
579 | public function ProductsPerPage() |
||
580 | { |
||
581 | return $this->MyNumberOfProductsPerPage(); |
||
582 | } |
||
583 | public function MyNumberOfProductsPerPage() |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a
Loading history...
|
|||
584 | { |
||
585 | $productsPagePage = 0; |
||
0 ignored issues
–
show
$productsPagePage is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the
Loading history...
|
|||
586 | if ($this->NumberOfProductsPerPage) { |
||
587 | $productsPagePage = $this->NumberOfProductsPerPage; |
||
588 | } else { |
||
589 | if ($parent = $this->ParentGroup()) { |
||
590 | $productsPagePage = $parent->MyNumberOfProductsPerPage(); |
||
591 | } else { |
||
592 | $productsPagePage = $this->EcomConfig()->NumberOfProductsPerPage; |
||
593 | } |
||
594 | } |
||
595 | |||
596 | return $productsPagePage; |
||
597 | } |
||
598 | |||
599 | /********************* |
||
600 | * SETTINGS: level of products to show |
||
601 | *********************/ |
||
602 | |||
603 | /** |
||
604 | * returns the number of product groups (children) |
||
605 | * to show in the current product list |
||
606 | * based on the user setting for this page. |
||
607 | * |
||
608 | * @return int |
||
609 | */ |
||
610 | public function MyLevelOfProductsToShow() |
||
611 | { |
||
612 | if ($this->LevelOfProductsToShow == 0) { |
||
613 | if ($parent = $this->ParentGroup()) { |
||
614 | $this->LevelOfProductsToShow = $parent->MyLevelOfProductsToShow(); |
||
615 | } |
||
616 | } |
||
617 | //reset to default |
||
618 | if ($this->LevelOfProductsToShow == 0) { |
||
619 | $defaults = Config::inst()->get('ProductGroup', 'defaults'); |
||
620 | |||
621 | return isset($defaults['LevelOfProductsToShow']) ? $defaults['LevelOfProductsToShow'] : 99; |
||
622 | } |
||
623 | |||
624 | return $this->LevelOfProductsToShow; |
||
625 | } |
||
626 | |||
627 | /********************* |
||
628 | * CMS Fields |
||
629 | *********************/ |
||
630 | |||
631 | /** |
||
632 | * standard SS method. |
||
633 | * |
||
634 | * @return FieldList |
||
635 | */ |
||
636 | public function getCMSFields() |
||
637 | { |
||
638 | $fields = parent::getCMSFields(); |
||
639 | //dirty hack to show images! |
||
640 | $fields->addFieldToTab('Root.Images', Product_ProductImageUploadField::create('Image', _t('Product.IMAGE', 'Product Group Image'))); |
||
641 | //number of products |
||
642 | $calculatedNumberOfProductsPerPage = $this->MyNumberOfProductsPerPage(); |
||
643 | $numberOfProductsPerPageExplanation = $calculatedNumberOfProductsPerPage != $this->NumberOfProductsPerPage ? _t('ProductGroup.CURRENTLVALUE', 'Current value: ').$calculatedNumberOfProductsPerPage.' '._t('ProductGroup.INHERITEDFROMPARENTSPAGE', ' (inherited from parent page because the current page is set to zero)') : ''; |
||
644 | $fields->addFieldToTab( |
||
645 | 'Root', |
||
646 | Tab::create( |
||
647 | 'ProductDisplay', |
||
648 | _t('ProductGroup.DISPLAY', 'Display'), |
||
649 | $productsToShowField = DropdownField::create('LevelOfProductsToShow', _t('ProductGroup.PRODUCTSTOSHOW', 'Products to show'), $this->showProductLevels), |
||
650 | HeaderField::create('WhatProductsAreShown', _t('ProductGroup.WHATPRODUCTSSHOWN', _t('ProductGroup.OPTIONSSELECTEDBELOWAPPLYTOCHILDGROUPS', 'Inherited options'))), |
||
651 | $numberOfProductsPerPageField = NumericField::create('NumberOfProductsPerPage', _t('ProductGroup.PRODUCTSPERPAGE', 'Number of products per page')) |
||
652 | ) |
||
653 | ); |
||
654 | $numberOfProductsPerPageField->setRightTitle($numberOfProductsPerPageExplanation); |
||
655 | if ($calculatedNumberOfProductsPerPage && !$this->NumberOfProductsPerPage) { |
||
656 | $this->NumberOfProductsPerPage = null; |
||
657 | $numberOfProductsPerPageField->setAttribute('placeholder', $calculatedNumberOfProductsPerPage); |
||
658 | } |
||
659 | //sort |
||
660 | $sortDropdownList = $this->getUserPreferencesOptionsForDropdown('SORT'); |
||
661 | if (count($sortDropdownList) > 1) { |
||
662 | $sortOrderKey = $this->getMyUserPreferencesDefault('SORT'); |
||
663 | if ($this->DefaultSortOrder == 'inherit') { |
||
664 | $actualValue = ' ('.(isset($sortDropdownList[$sortOrderKey]) ? $sortDropdownList[$sortOrderKey] : _t('ProductGroup.ERROR', 'ERROR')).')'; |
||
665 | $sortDropdownList['inherit'] = _t('ProductGroup.INHERIT', 'Inherit').$actualValue; |
||
666 | } |
||
667 | $fields->addFieldToTab( |
||
668 | 'Root.ProductDisplay', |
||
669 | $defaultSortOrderField = DropdownField::create('DefaultSortOrder', _t('ProductGroup.DEFAULTSORTORDER', 'Default Sort Order'), $sortDropdownList) |
||
670 | ); |
||
671 | $defaultSortOrderField->setRightTitle(_t('ProductGroup.INHERIT_RIGHT_TITLE', "Inherit means that the parent page value is used - and if there is no relevant parent page then the site's default value is used.")); |
||
672 | } |
||
673 | //filter |
||
674 | $filterDropdownList = $this->getUserPreferencesOptionsForDropdown('FILTER'); |
||
675 | if (count($filterDropdownList) > 1) { |
||
676 | $filterKey = $this->getMyUserPreferencesDefault('FILTER'); |
||
677 | if ($this->DefaultFilter == 'inherit') { |
||
678 | $actualValue = ' ('.(isset($filterDropdownList[$filterKey]) ? $filterDropdownList[$filterKey] : _t('ProductGroup.ERROR', 'ERROR')).')'; |
||
679 | $filterDropdownList['inherit'] = _t('ProductGroup.INHERIT', 'Inherit').$actualValue; |
||
680 | } |
||
681 | $fields->addFieldToTab( |
||
682 | 'Root.ProductDisplay', |
||
683 | $defaultFilterField = DropdownField::create('DefaultFilter', _t('ProductGroup.DEFAULTFILTER', 'Default Filter'), $filterDropdownList) |
||
684 | ); |
||
685 | $defaultFilterField->setRightTitle(_t('ProductGroup.INHERIT_RIGHT_TITLE', "Inherit means that the parent page value is used - and if there is no relevant parent page then the site's default value is used.")); |
||
686 | } |
||
687 | //display style |
||
688 | $displayStyleDropdownList = $this->getUserPreferencesOptionsForDropdown('DISPLAY'); |
||
689 | if (count($displayStyleDropdownList) > 2) { |
||
690 | $displayStyleKey = $this->getMyUserPreferencesDefault('DISPLAY'); |
||
691 | if ($this->DisplayStyle == 'inherit') { |
||
692 | $actualValue = ' ('.(isset($displayStyleDropdownList[$displayStyleKey]) ? $displayStyleDropdownList[$displayStyleKey] : _t('ProductGroup.ERROR', 'ERROR')).')'; |
||
693 | $displayStyleDropdownList['inherit'] = _t('ProductGroup.INHERIT', 'Inherit').$actualValue; |
||
694 | } |
||
695 | $fields->addFieldToTab( |
||
696 | 'Root.ProductDisplay', |
||
697 | DropdownField::create('DisplayStyle', _t('ProductGroup.DEFAULTDISPLAYSTYLE', 'Default Display Style'), $displayStyleDropdownList) |
||
698 | ); |
||
699 | } |
||
700 | if ($this->EcomConfig()->ProductsAlsoInOtherGroups) { |
||
701 | if (!$this instanceof ProductGroupSearchPage) { |
||
702 | $fields->addFieldsToTab( |
||
703 | 'Root.OtherProductsShown', |
||
704 | array( |
||
705 | HeaderField::create('ProductGroupsHeader', _t('ProductGroup.OTHERPRODUCTSTOSHOW', 'Other products to show ...')), |
||
706 | $this->getProductGroupsTable(), |
||
707 | ) |
||
708 | ); |
||
709 | } |
||
710 | } |
||
711 | |||
712 | return $fields; |
||
713 | } |
||
714 | |||
715 | /** |
||
716 | * used if you install lumberjack |
||
717 | * @return string |
||
718 | */ |
||
719 | public function getLumberjackTitle() |
||
720 | { |
||
721 | return _t('ProductGroup.BUYABLES', 'Products'); |
||
722 | } |
||
723 | |||
724 | // /** |
||
725 | // * used if you install lumberjack |
||
726 | // * @return string |
||
727 | // */ |
||
728 | // public function getLumberjackGridFieldConfig() |
||
729 | // { |
||
730 | // return GridFieldConfig_RelationEditor::create(); |
||
731 | // } |
||
732 | |||
733 | /** |
||
734 | * Used in getCSMFields. |
||
735 | * |
||
736 | * @return GridField |
||
737 | **/ |
||
738 | protected function getProductGroupsTable() |
||
739 | { |
||
740 | $gridField = GridField::create( |
||
741 | 'AlsoShowProducts', |
||
742 | _t('ProductGroup.OTHER_PRODUCTS_SHOWN_IN_THIS_GROUP', 'Other products shown in this group ...'), |
||
743 | $this->AlsoShowProducts(), |
||
744 | GridFieldBasicPageRelationConfig::create() |
||
745 | ); |
||
746 | //make sure edits are done in the right place ... |
||
747 | return $gridField; |
||
748 | } |
||
749 | |||
750 | /***************************************************** |
||
751 | * |
||
752 | * |
||
753 | * |
||
754 | * PRODUCTS THAT BELONG WITH THIS PRODUCT GROUP |
||
755 | * |
||
756 | * |
||
757 | * |
||
758 | *****************************************************/ |
||
759 | |||
760 | /** |
||
761 | * returns the inital (all) products, based on the all the eligible products |
||
762 | * for the page. |
||
763 | * |
||
764 | * This is THE pivotal method that probably changes for classes that |
||
765 | * extend ProductGroup as here you can determine what products or other buyables are shown. |
||
766 | * |
||
767 | * The return from this method will then be sorted to produce the final product list. |
||
768 | * |
||
769 | * There is no sort for the initial retrieval |
||
770 | * |
||
771 | * This method is public so that you can retrieve a list of products for a product group page. |
||
772 | * |
||
773 | * @param array | string $extraFilter Additional SQL filters to apply to the Product retrieval |
||
774 | * @param string $alternativeFilterKey Alternative standard filter to be used. |
||
775 | * |
||
776 | * @return DataList |
||
777 | **/ |
||
778 | public function currentInitialProducts($extraFilter = null, $alternativeFilterKey = '') |
||
779 | { |
||
780 | |||
781 | //INIT ALLPRODUCTS |
||
782 | unset($this->allProducts); |
||
783 | $className = $this->getBuyableClassName(); |
||
784 | $this->allProducts = $className::get(); |
||
785 | |||
786 | // GROUP FILTER (PRODUCTS FOR THIS GROUP) |
||
787 | $this->allProducts = $this->getGroupFilter(); |
||
788 | |||
789 | // STANDARD FILTER (INCLUDES USER PREFERENCE) |
||
790 | $filterStatement = $this->allowPurchaseWhereStatement(); |
||
791 | if ($filterStatement) { |
||
792 | if (is_array($filterStatement)) { |
||
793 | $this->allProducts = $this->allProducts->filter($filterStatement); |
||
794 | } elseif (is_string($filterStatement)) { |
||
795 | $this->allProducts = $this->allProducts->where($filterStatement); |
||
796 | } |
||
797 | } |
||
798 | $this->allProducts = $this->getStandardFilter($alternativeFilterKey); |
||
799 | |||
800 | // EXTRA FILTER (ON THE FLY FROM CONTROLLER) |
||
801 | if (is_array($extraFilter) && count($extraFilter)) { |
||
802 | $this->allProducts = $this->allProducts->filter($extraFilter); |
||
803 | } elseif (is_string($extraFilter) && strlen($extraFilter) > 2) { |
||
804 | $this->allProducts = $this->allProducts->where($extraFilter); |
||
805 | } |
||
806 | |||
807 | //JOINS |
||
808 | $this->allProducts = $this->getGroupJoin(); |
||
809 | |||
810 | return $this->allProducts; |
||
811 | } |
||
812 | |||
813 | /** |
||
814 | * this method can be used quickly current initial products |
||
815 | * whenever you write: |
||
816 | * ```php |
||
817 | * currentInitialProducts->(null, $key)->map("ID", "ID")->toArray(); |
||
818 | * ``` |
||
819 | * this is the better replacement. |
||
820 | * |
||
821 | * @param string $filterKey |
||
822 | * |
||
823 | * @return array |
||
824 | */ |
||
825 | public function currentInitialProductsAsCachedArray($filterKey) |
||
826 | { |
||
827 | $cacheKey = 'CurrentInitialProductsArray'.$filterKey; |
||
828 | if ($array = $this->retrieveObjectStore($cacheKey)) { |
||
829 | //do nothing |
||
830 | } else { |
||
831 | $array = $this->currentInitialProducts(null, $filterKey)->map('ID', 'ID')->toArray(); |
||
832 | $this->saveObjectStore($array, $cacheKey); |
||
833 | } |
||
834 | |||
835 | return $array; |
||
836 | } |
||
837 | |||
838 | /***************************************************** |
||
839 | * DATALIST: adjusters |
||
840 | * these are the methods you want to override in |
||
841 | * any clases that extend ProductGroup |
||
842 | *****************************************************/ |
||
843 | |||
844 | /** |
||
845 | * Do products occur in more than one group. |
||
846 | * |
||
847 | * @return bool |
||
848 | */ |
||
849 | protected function getProductsAlsoInOtherGroups() |
||
850 | { |
||
851 | return $this->EcomConfig()->ProductsAlsoInOtherGroups; |
||
852 | } |
||
853 | |||
854 | /** |
||
855 | * Returns the class we are working with. |
||
856 | * |
||
857 | * @return string |
||
0 ignored issues
–
show
|
|||
858 | */ |
||
859 | protected function getBuyableClassName() |
||
860 | { |
||
861 | return EcommerceConfig::get('ProductGroup', 'base_buyable_class'); |
||
862 | } |
||
863 | |||
864 | /** |
||
865 | * @SEE: important notes at the top of this file / class |
||
866 | * |
||
867 | * IMPORTANT: Adjusts allProducts and returns it... |
||
868 | * |
||
869 | * @return DataList |
||
870 | */ |
||
871 | protected function getGroupFilter() |
||
872 | { |
||
873 | $levelToShow = $this->MyLevelOfProductsToShow(); |
||
874 | $cacheKey = 'GroupFilter_'.abs(intval($levelToShow + 999)); |
||
875 | if ($groupFilter = $this->retrieveObjectStore($cacheKey)) { |
||
876 | $this->allProducts = $this->allProducts->where($groupFilter); |
||
877 | } else { |
||
878 | $groupFilter = ''; |
||
0 ignored issues
–
show
$groupFilter is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the
Loading history...
|
|||
879 | $productFilterArray = array(); |
||
880 | //special cases |
||
881 | if ($levelToShow < 0) { |
||
882 | //no produts but if LevelOfProductsToShow = -1 then show all |
||
883 | $groupFilter = ' ('.$levelToShow.' = -1) '; |
||
884 | } elseif ($levelToShow > 0) { |
||
885 | $groupIDs = array($this->ID => $this->ID); |
||
886 | $productFilterTemp = $this->getProductsToBeIncludedFromOtherGroups(); |
||
887 | $productFilterArray[$productFilterTemp] = $productFilterTemp; |
||
888 | $childGroups = $this->ChildGroups($levelToShow); |
||
889 | if ($childGroups && $childGroups->count()) { |
||
890 | foreach ($childGroups as $childGroup) { |
||
891 | $groupIDs[$childGroup->ID] = $childGroup->ID; |
||
892 | $productFilterTemp = $childGroup->getProductsToBeIncludedFromOtherGroups(); |
||
893 | $productFilterArray[$productFilterTemp] = $productFilterTemp; |
||
894 | } |
||
895 | } |
||
896 | $groupFilter = ' ( "ParentID" IN ('.implode(',', $groupIDs).') ) '.implode($productFilterArray).' '; |
||
897 | } else { |
||
898 | //fall-back |
||
899 | $groupFilter = '"ParentID" < 0'; |
||
900 | } |
||
901 | $this->allProducts = $this->allProducts->where($groupFilter); |
||
902 | $this->saveObjectStore($groupFilter, $cacheKey); |
||
903 | } |
||
904 | |||
905 | return $this->allProducts; |
||
906 | } |
||
907 | |||
908 | /** |
||
909 | * If products are show in more than one group |
||
910 | * Then this returns a where phrase for any products that are linked to this |
||
911 | * product group. |
||
912 | * |
||
913 | * @return string |
||
914 | */ |
||
915 | protected function getProductsToBeIncludedFromOtherGroups() |
||
916 | { |
||
917 | //TO DO: this should actually return |
||
918 | //Product.ID = IN ARRAY(bla bla) |
||
919 | $array = array(); |
||
920 | if ($this->getProductsAlsoInOtherGroups()) { |
||
921 | $array = $this->AlsoShowProducts()->map('ID', 'ID')->toArray(); |
||
922 | } |
||
923 | if (count($array)) { |
||
924 | return " OR (\"Product\".\"ID\" IN (".implode(',', $array).')) '; |
||
925 | } |
||
926 | |||
927 | return ''; |
||
928 | } |
||
929 | |||
930 | /** |
||
931 | * @SEE: important notes at the top of this class / file for more information! |
||
932 | * |
||
933 | * IMPORTANT: Adjusts allProducts and returns it... |
||
934 | * |
||
935 | * @param string $alternativeFilterKey - filter key to be used... if none is specified then we use the current one. |
||
936 | * |
||
937 | * @return DataList |
||
938 | */ |
||
939 | protected function getStandardFilter($alternativeFilterKey = '') |
||
940 | { |
||
941 | if ($alternativeFilterKey) { |
||
942 | $filterKey = $alternativeFilterKey; |
||
943 | } else { |
||
944 | $filterKey = $this->getCurrentUserPreferences('FILTER'); |
||
945 | } |
||
946 | $filter = $this->getUserSettingsOptionSQL('FILTER', $filterKey); |
||
947 | if (is_array($filter)) { |
||
948 | $this->allProducts = $this->allProducts->Filter($filter); |
||
949 | } elseif (is_string($filter) && strlen($filter) > 2) { |
||
950 | $this->allProducts = $this->allProducts->Where($filter); |
||
951 | } |
||
952 | |||
953 | return $this->allProducts; |
||
954 | } |
||
955 | |||
956 | /** |
||
957 | * Join statement for the product groups. |
||
958 | * |
||
959 | * IMPORTANT: Adjusts allProducts and returns it... |
||
960 | * |
||
961 | * @return DataList |
||
962 | */ |
||
963 | protected function getGroupJoin() |
||
964 | { |
||
965 | return $this->allProducts; |
||
966 | } |
||
967 | |||
968 | /** |
||
969 | * Quick - dirty hack - filter to |
||
970 | * only show relevant products. |
||
971 | * |
||
972 | * @param bool $asArray |
||
973 | * @param string $table |
||
974 | */ |
||
975 | protected function allowPurchaseWhereStatement($asArray = true, $table = 'Product') |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a
Loading history...
|
|||
976 | { |
||
977 | if ($this->EcomConfig()->OnlyShowProductsThatCanBePurchased) { |
||
978 | if ($asArray) { |
||
979 | $allowPurchaseWhereStatement = array('AllowPurchase' => 1); |
||
980 | } else { |
||
981 | $allowPurchaseWhereStatement = "\"$table\".\"AllowPurchase\" = 1 "; |
||
982 | } |
||
983 | |||
984 | return $allowPurchaseWhereStatement; |
||
985 | } |
||
986 | } |
||
987 | |||
988 | /***************************************************** |
||
989 | * |
||
990 | * |
||
991 | * |
||
992 | * |
||
993 | * FINAL PRODUCTS |
||
994 | * |
||
995 | * |
||
996 | * |
||
997 | * |
||
998 | *****************************************************/ |
||
999 | |||
1000 | /** |
||
1001 | * This is the dataList that contains all the products. |
||
1002 | * |
||
1003 | * @var DataList |
||
1004 | */ |
||
1005 | protected $allProducts = null; |
||
1006 | |||
1007 | /** |
||
1008 | * a list of relevant buyables that can |
||
1009 | * not be purchased and therefore should be excluded. |
||
1010 | * Should be set to NULL to start with so we know if it has been |
||
1011 | * set yet. |
||
1012 | * |
||
1013 | * @var null | Array (like so: array(1,2,4,5,99)) |
||
1014 | */ |
||
1015 | private $canNOTbePurchasedArray = null; |
||
1016 | |||
1017 | /** |
||
1018 | * a list of relevant buyables that can |
||
1019 | * be purchased. We keep this so that |
||
1020 | * that we can save to session, etc... for future use. |
||
1021 | * Should be set to NULL to start with so we know if it has been |
||
1022 | * set yet. |
||
1023 | * |
||
1024 | * @var null | Array (like so: array(1,2,4,5,99)) |
||
1025 | */ |
||
1026 | protected $canBePurchasedArray = null; |
||
1027 | |||
1028 | /** |
||
1029 | * returns the total numer of products (before pagination). |
||
1030 | * |
||
1031 | * @return int |
||
1032 | **/ |
||
1033 | public function RawCount() |
||
1034 | { |
||
1035 | return $this->rawCount ? $this->rawCount : 0; |
||
1036 | } |
||
1037 | |||
1038 | /** |
||
1039 | * returns the total numer of products (before pagination). |
||
1040 | * |
||
1041 | * @return int |
||
1042 | **/ |
||
1043 | public function TotalCount() |
||
1044 | { |
||
1045 | return $this->totalCount ? $this->totalCount : 0; |
||
1046 | } |
||
1047 | |||
1048 | /** |
||
1049 | * this is used to save a list of sorted products |
||
1050 | * so that you can find a previous and a next button, etc... |
||
1051 | * |
||
1052 | * @return array |
||
0 ignored issues
–
show
|
|||
1053 | */ |
||
1054 | public function getProductsThatCanBePurchasedArray() |
||
1055 | { |
||
1056 | return $this->canBePurchasedArray; |
||
1057 | } |
||
1058 | |||
1059 | /** |
||
1060 | * Retrieve a set of products, based on the given parameters. |
||
1061 | * This method is usually called by the various controller methods. |
||
1062 | * The extraFilter helps you to select different products, |
||
1063 | * depending on the method used in the controller. |
||
1064 | * |
||
1065 | * Furthermore, extrafilter can take all sorts of variables. |
||
1066 | * This is basically setup like this so that in ProductGroup extensions you |
||
1067 | * can setup all sorts of filters, while still using the ProductsShowable method. |
||
1068 | * |
||
1069 | * The extra filter can be supplied as array (e.g. array("ID" => 12) or array("ID" => array(12,13,45))) |
||
1070 | * or as string. Arrays are used like this $productDataList->filter($array) and |
||
1071 | * strings are used with the where commands $productDataList->where($string). |
||
1072 | * |
||
1073 | * @param array | string $extraFilter Additional SQL filters to apply to the Product retrieval |
||
1074 | * @param array | string $alternativeSort Additional SQL for sorting |
||
1075 | * @param string $alternativeFilterKey alternative filter key to be used |
||
1076 | * |
||
1077 | * @return DataList | Null |
||
0 ignored issues
–
show
|
|||
1078 | */ |
||
1079 | public function ProductsShowable($extraFilter = null, $alternativeSort = null, $alternativeFilterKey = '') |
||
1080 | { |
||
1081 | |||
1082 | //get original products without sort |
||
1083 | $this->allProducts = $this->currentInitialProducts($extraFilter, $alternativeFilterKey); |
||
1084 | |||
1085 | //sort products |
||
1086 | $this->allProducts = $this->currentFinalProducts($alternativeSort); |
||
1087 | |||
1088 | return $this->allProducts; |
||
1089 | } |
||
1090 | |||
1091 | /** |
||
1092 | * returns the final products, based on the all the eligile products |
||
1093 | * for the page. |
||
1094 | * |
||
1095 | * In the process we also save a list of included products |
||
1096 | * and we sort them. We also keep a record of the total count. |
||
1097 | * |
||
1098 | * All of the 'current' methods are to support the currentFinalProducts Method. |
||
1099 | * |
||
1100 | * @TODO: cache data for faster access. |
||
1101 | * |
||
1102 | * @param array | string $alternativeSort = Alternative Sort String or array |
||
1103 | * |
||
1104 | * @return DataList |
||
0 ignored issues
–
show
|
|||
1105 | **/ |
||
1106 | protected function currentFinalProducts($alternativeSort = null) |
||
1107 | { |
||
1108 | if ($this->allProducts) { |
||
1109 | |||
1110 | //limit to maximum number of products for speed's sake |
||
1111 | $this->allProducts = $this->sortCurrentFinalProducts($alternativeSort); |
||
1112 | $this->allProducts = $this->limitCurrentFinalProducts(); |
||
1113 | $this->allProducts = $this->removeExcludedProductsAndSaveIncludedProducts($this->allProducts); |
||
1114 | |||
1115 | return $this->allProducts; |
||
1116 | } |
||
1117 | } |
||
1118 | |||
1119 | /** |
||
1120 | * returns the SORT part of the final selection of products. |
||
1121 | * |
||
1122 | * @return DataList (allProducts) |
||
1123 | */ |
||
1124 | protected function sortCurrentFinalProducts($alternativeSort) |
||
1125 | { |
||
1126 | if ($alternativeSort) { |
||
1127 | if ($this->IsIDarray($alternativeSort)) { |
||
1128 | $sort = $this->createSortStatementFromIDArray($alternativeSort); |
||
1129 | } else { |
||
1130 | $sort = $alternativeSort; |
||
1131 | } |
||
1132 | } else { |
||
1133 | $sort = $this->currentSortSQL(); |
||
1134 | } |
||
1135 | $this->allProducts = $this->allProducts->Sort($sort); |
||
1136 | |||
1137 | return $this->allProducts; |
||
1138 | } |
||
1139 | |||
1140 | /** |
||
1141 | * is the variable provided is an array |
||
1142 | * that can be used as a list of IDs? |
||
1143 | * |
||
1144 | * @param mixed |
||
1145 | * |
||
1146 | * @return bool |
||
1147 | */ |
||
1148 | protected function IsIDarray($variable) |
||
1149 | { |
||
1150 | return $variable && is_array($variable) && count($variable) && intval(current($variable)) == current($variable); |
||
1151 | } |
||
1152 | |||
1153 | /** |
||
1154 | * returns the SORT part of the final selection of products. |
||
1155 | * |
||
1156 | * @return string | Array |
||
0 ignored issues
–
show
|
|||
1157 | */ |
||
1158 | protected function currentSortSQL() |
||
1159 | { |
||
1160 | $sortKey = $this->getCurrentUserPreferences('SORT'); |
||
1161 | |||
1162 | return $this->getUserSettingsOptionSQL('SORT', $sortKey); |
||
1163 | } |
||
1164 | |||
1165 | /** |
||
1166 | * creates a sort string from a list of ID arrays... |
||
1167 | * |
||
1168 | * @param array $IDarray - list of product IDs |
||
1169 | * |
||
1170 | * @return string |
||
1171 | */ |
||
1172 | protected function createSortStatementFromIDArray($IDarray, $table = 'Product') |
||
1173 | { |
||
1174 | $ifStatement = 'CASE '; |
||
1175 | $sortStatement = ''; |
||
0 ignored issues
–
show
$sortStatement is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the
Loading history...
|
|||
1176 | $stage = $this->getStage(); |
||
1177 | $count = 0; |
||
1178 | foreach ($IDarray as $productID) { |
||
1179 | $ifStatement .= ' WHEN "'.$table.$stage."\".\"ID\" = $productID THEN $count"; |
||
1180 | ++$count; |
||
1181 | } |
||
1182 | $sortStatement = $ifStatement.' END'; |
||
1183 | |||
1184 | return $sortStatement; |
||
1185 | } |
||
1186 | |||
1187 | /** |
||
1188 | * limits the products to a maximum number (for speed's sake). |
||
1189 | * |
||
1190 | * @return DataList (this->allProducts adjusted!) |
||
1191 | */ |
||
1192 | protected function limitCurrentFinalProducts() |
||
1193 | { |
||
1194 | $this->rawCount = $this->allProducts->count(); |
||
1195 | $max = EcommerceConfig::get('ProductGroup', 'maximum_number_of_products_to_list'); |
||
1196 | if ($this->rawCount > $max) { |
||
1197 | $this->allProducts = $this->allProducts->limit($max); |
||
1198 | $this->totalCount = $max; |
||
1199 | } else { |
||
1200 | $this->totalCount = $this->rawCount; |
||
1201 | } |
||
1202 | |||
1203 | return $this->allProducts; |
||
1204 | } |
||
1205 | |||
1206 | /** |
||
1207 | * Excluded products that can not be purchased |
||
1208 | * We all make a record of all the products that are in the current list |
||
1209 | * For efficiency sake, we do both these things at the same time. |
||
1210 | * IMPORTANT: Adjusts allProducts and returns it... |
||
1211 | * |
||
1212 | * @todo: cache data per user .... |
||
1213 | * |
||
1214 | * @return DataList |
||
1215 | */ |
||
1216 | protected function removeExcludedProductsAndSaveIncludedProducts() |
||
1217 | { |
||
1218 | if (is_array($this->canBePurchasedArray) && is_array($this->canNOTbePurchasedArray)) { |
||
1219 | //already done! |
||
1220 | } else { |
||
1221 | $this->canNOTbePurchasedArray = array(); |
||
0 ignored issues
–
show
It seems like
array() of type array is incompatible with the declared type null of property $canNOTbePurchasedArray .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..
Loading history...
|
|||
1222 | $this->canBePurchasedArray = array(); |
||
0 ignored issues
–
show
It seems like
array() of type array is incompatible with the declared type null of property $canBePurchasedArray .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..
Loading history...
|
|||
1223 | if ($this->config()->get('actively_check_for_can_purchase')) { |
||
1224 | foreach ($this->allProducts as $buyable) { |
||
1225 | if ($buyable->canPurchase()) { |
||
1226 | $this->canBePurchasedArray[$buyable->ID] = $buyable->ID; |
||
1227 | } else { |
||
1228 | $this->canNOTbePurchasedArray[$buyable->ID] = $buyable->ID; |
||
1229 | } |
||
1230 | } |
||
1231 | } else { |
||
1232 | if ($this->rawCount > 0) { |
||
1233 | $this->canBePurchasedArray = $this->allProducts->map('ID', 'ID')->toArray(); |
||
0 ignored issues
–
show
It seems like
$this->allProducts->map('ID', 'ID')->toArray() of type array is incompatible with the declared type null of property $canBePurchasedArray .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..
Loading history...
|
|||
1234 | } else { |
||
1235 | $this->canBePurchasedArray = array(); |
||
1236 | } |
||
1237 | } |
||
1238 | if (count($this->canNOTbePurchasedArray)) { |
||
1239 | $this->allProducts = $this->allProducts->Exclude(array('ID' => $this->canNOTbePurchasedArray)); |
||
1240 | } |
||
1241 | } |
||
1242 | |||
1243 | return $this->allProducts; |
||
1244 | } |
||
1245 | |||
1246 | /***************************************************** |
||
1247 | * Children and Parents |
||
1248 | *****************************************************/ |
||
1249 | |||
1250 | /** |
||
1251 | * Returns children ProductGroup pages of this group. |
||
1252 | * |
||
1253 | * @param int $maxRecursiveLevel - maximum depth , e.g. 1 = one level down - so no Child Groups are returned... |
||
1254 | * @param string | Array $filter - additional filter to be added |
||
1255 | * @param int $numberOfRecursions - current level of depth |
||
1256 | * |
||
1257 | * @return ArrayList (ProductGroups) |
||
1258 | */ |
||
1259 | public function ChildGroups($maxRecursiveLevel, $filter = null, $numberOfRecursions = 0) |
||
1260 | { |
||
1261 | $arrayList = ArrayList::create(); |
||
1262 | ++$numberOfRecursions; |
||
1263 | if ($numberOfRecursions < $maxRecursiveLevel) { |
||
1264 | if ($filter && is_string($filter)) { |
||
1265 | $filterWithAND = " AND $filter"; |
||
1266 | $where = "\"ParentID\" = '$this->ID' $filterWithAND"; |
||
1267 | $children = ProductGroup::get()->where($where); |
||
1268 | } elseif (is_array($filter) && count($filter)) { |
||
1269 | $filter = $filter + array('ParentID' => $this->ID); |
||
1270 | $children = ProductGroup::get()->filter($filter); |
||
1271 | } else { |
||
1272 | $children = ProductGroup::get()->filter(array('ParentID' => $this->ID)); |
||
1273 | } |
||
1274 | |||
1275 | if ($children->count()) { |
||
1276 | foreach ($children as $child) { |
||
1277 | $arrayList->push($child); |
||
1278 | $arrayList->merge($child->ChildGroups($maxRecursiveLevel, $filter, $numberOfRecursions)); |
||
1279 | } |
||
1280 | } |
||
1281 | } |
||
1282 | if (!$arrayList instanceof ArrayList) { |
||
1283 | user_error('We expect an array list as output'); |
||
1284 | } |
||
1285 | |||
1286 | return $arrayList; |
||
1287 | } |
||
1288 | |||
1289 | /** |
||
1290 | * Deprecated method. |
||
1291 | */ |
||
1292 | public function ChildGroupsBackup($maxRecursiveLevel, $filter = '') |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a
Loading history...
|
|||
1293 | { |
||
1294 | Deprecation::notice('3.1', 'No longer in use'); |
||
1295 | if ($maxRecursiveLevel > 24) { |
||
1296 | $maxRecursiveLevel = 24; |
||
1297 | } |
||
1298 | |||
1299 | $stage = $this->getStage(); |
||
1300 | $select = 'P1.ID as ID1 '; |
||
1301 | $from = "ProductGroup$stage as P1 "; |
||
1302 | $join = " INNER JOIN SiteTree$stage AS S1 ON P1.ID = S1.ID"; |
||
1303 | $where = '1 = 1'; |
||
1304 | $ids = array(-1); |
||
1305 | for ($i = 1; $i < $maxRecursiveLevel; ++$i) { |
||
1306 | $j = $i + 1; |
||
1307 | $select .= ", P$j.ID AS ID$j, S$j.ParentID"; |
||
1308 | $join .= " |
||
1309 | LEFT JOIN ProductGroup$stage AS P$j ON P$j.ID = S$i.ParentID |
||
1310 | LEFT JOIN SiteTree$stage AS S$j ON P$j.ID = S$j.ID |
||
1311 | "; |
||
1312 | } |
||
1313 | $rows = DB::Query(' SELECT '.$select.' FROM '.$from.$join.' WHERE '.$where); |
||
1314 | if ($rows) { |
||
1315 | foreach ($rows as $row) { |
||
1316 | for ($i = 1; $i < $maxRecursiveLevel; ++$i) { |
||
1317 | if ($row['ID'.$i]) { |
||
1318 | $ids[$row['ID'.$i]] = $row['ID'.$i]; |
||
1319 | } |
||
1320 | } |
||
1321 | } |
||
1322 | } |
||
1323 | |||
1324 | return ProductGroup::get()->where("\"ProductGroup$stage\".\"ID\" IN (".implode(',', $ids).')'.$filterWithAND); |
||
0 ignored issues
–
show
The variable
$filterWithAND does not exist. Did you mean $filter ?
This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name. The variable may have been renamed without also renaming all references.
Loading history...
|
|||
1325 | } |
||
1326 | |||
1327 | /** |
||
1328 | * returns the parent page, but only if it is an instance of Product Group. |
||
1329 | * |
||
1330 | * @return DataObject | Null (ProductGroup) |
||
1331 | **/ |
||
1332 | public function ParentGroup() |
||
1333 | { |
||
1334 | if ($this->ParentID) { |
||
1335 | return ProductGroup::get()->byID($this->ParentID); |
||
1336 | } |
||
1337 | } |
||
1338 | |||
1339 | /***************************************************** |
||
1340 | * Other Stuff |
||
1341 | *****************************************************/ |
||
1342 | |||
1343 | /** |
||
1344 | * Recursively generate a product menu. |
||
1345 | * |
||
1346 | * @param string $filter |
||
1347 | * |
||
1348 | * @return ArrayList (ProductGroups) |
||
1349 | */ |
||
1350 | public function GroupsMenu($filter = 'ShowInMenus = 1') |
||
1351 | { |
||
1352 | if ($parent = $this->ParentGroup()) { |
||
1353 | return is_a($parent, Object::getCustomClass('ProductGroup')) ? $parent->GroupsMenu() : $this->ChildGroups($filter); |
||
1354 | } else { |
||
1355 | return $this->ChildGroups($filter); |
||
1356 | } |
||
1357 | } |
||
1358 | |||
1359 | /** |
||
1360 | * returns a "BestAvailable" image if the current one is not available |
||
1361 | * In some cases this is appropriate and in some cases this is not. |
||
1362 | * For example, consider the following setup |
||
1363 | * - product A with three variations |
||
1364 | * - Product A has an image, but the variations have no images |
||
1365 | * With this scenario, you want to show ONLY the product image |
||
1366 | * on the product page, but if one of the variations is added to the |
||
1367 | * cart, then you want to show the product image. |
||
1368 | * This can be achieved bu using the BestAvailable image. |
||
1369 | * |
||
1370 | * @return Image | Null |
||
1371 | */ |
||
1372 | public function BestAvailableImage() |
||
1373 | { |
||
1374 | $image = $this->Image(); |
||
1375 | if ($image && $image->exists() && file_exists($image->getFullPath())) { |
||
1376 | return $image; |
||
1377 | } elseif ($parent = $this->ParentGroup()) { |
||
1378 | return $parent->BestAvailableImage(); |
||
1379 | } |
||
1380 | } |
||
1381 | |||
1382 | /***************************************************** |
||
1383 | * Other related products |
||
1384 | *****************************************************/ |
||
1385 | |||
1386 | /** |
||
1387 | * returns a list of Product Groups that have the products for |
||
1388 | * the CURRENT product group listed as part of their AlsoShowProducts list. |
||
1389 | * |
||
1390 | * EXAMPLE: |
||
1391 | * You can use the AlsoShowProducts to list products by Brand. |
||
1392 | * In general, they are listed under type product groups (e.g. socks, sweaters, t-shirts), |
||
1393 | * and you create a list of separate ProductGroups (brands) that do not have ANY products as children, |
||
1394 | * but link to products using the AlsoShowProducts many_many relation. |
||
1395 | * |
||
1396 | * With the method below you can work out a list of brands that apply to the |
||
1397 | * current product group (e.g. socks come in three brands - namely A, B and C) |
||
1398 | * |
||
1399 | * @return DataList |
||
1400 | */ |
||
1401 | public function ProductGroupsFromAlsoShowProducts() |
||
1402 | { |
||
1403 | $parentIDs = array(); |
||
1404 | //we need to add the last array to make sure we have some products... |
||
1405 | $myProductsArray = $this->currentInitialProductsAsCachedArray($this->getMyUserPreferencesDefault('FILTER')); |
||
1406 | $rows = array(); |
||
1407 | if (count($myProductsArray)) { |
||
1408 | $rows = DB::query(' |
||
1409 | SELECT "ProductGroupID" |
||
1410 | FROM "Product_ProductGroups" |
||
1411 | WHERE "ProductID" IN ('.implode(',', $myProductsArray).') |
||
1412 | GROUP BY "ProductGroupID"; |
||
1413 | '); |
||
1414 | } |
||
1415 | foreach ($rows as $row) { |
||
1416 | $parentIDs[$row['ProductGroupID']] = $row['ProductGroupID']; |
||
1417 | } |
||
1418 | //just in case |
||
1419 | unset($parentIDs[$this->ID]); |
||
1420 | if (!count($parentIDs)) { |
||
1421 | $parentIDs = array(0 => 0); |
||
1422 | } |
||
1423 | |||
1424 | return ProductGroup::get()->filter(array('ID' => $parentIDs, 'ShowInSearch' => 1)); |
||
1425 | } |
||
1426 | |||
1427 | /** |
||
1428 | * This is the inverse of ProductGroupsFromAlsoShowProducts |
||
1429 | * That is, it list the product groups that a product is primarily listed under (exact parents only) |
||
1430 | * from a "AlsoShow" product List. |
||
1431 | * |
||
1432 | * @return DataList |
||
1433 | */ |
||
1434 | public function ProductGroupsFromAlsoShowProductsInverse() |
||
1435 | { |
||
1436 | $alsoShowProductsArray = $this->AlsoShowProducts() |
||
1437 | ->filter($this->getUserSettingsOptionSQL('FILTER', $this->getMyUserPreferencesDefault('FILTER'))) |
||
1438 | ->map('ID', 'ID')->toArray(); |
||
1439 | $alsoShowProductsArray[0] = 0; |
||
1440 | $parentIDs = Product::get()->filter(array('ID' => $alsoShowProductsArray))->map('ParentID', 'ParentID')->toArray(); |
||
1441 | //just in case |
||
1442 | unset($parentIDs[$this->ID]); |
||
1443 | if (! count($parentIDs)) { |
||
1444 | $parentIDs = array(0 => 0); |
||
1445 | } |
||
1446 | |||
1447 | return ProductGroup::get()->filter(array('ID' => $parentIDs, 'ShowInMenus' => 1)); |
||
1448 | } |
||
1449 | |||
1450 | /** |
||
1451 | * given the products for this page, |
||
1452 | * retrieve the parent groups excluding the current one. |
||
1453 | * |
||
1454 | * @return DataList |
||
1455 | */ |
||
1456 | public function ProductGroupsParentGroups() |
||
1457 | { |
||
1458 | $arrayOfIDs = $this->currentInitialProductsAsCachedArray($this->getMyUserPreferencesDefault('FILTER')) + array(0 => 0); |
||
1459 | $parentIDs = Product::get()->filter(array('ID' => $arrayOfIDs))->map('ParentID', 'ParentID')->toArray(); |
||
1460 | //just in case |
||
1461 | unset($parentIDs[$this->ID]); |
||
1462 | if (! count($parentIDs)) { |
||
1463 | $parentIDs = array(0 => 0); |
||
1464 | } |
||
1465 | |||
1466 | return ProductGroup::get()->filter(array('ID' => $parentIDs, 'ShowInSearch' => 1)); |
||
1467 | } |
||
1468 | |||
1469 | /** |
||
1470 | * returns stage as "" or "_Live". |
||
1471 | * |
||
1472 | * @return string |
||
1473 | */ |
||
1474 | protected function getStage() |
||
1475 | { |
||
1476 | $stage = ''; |
||
1477 | if (Versioned::current_stage() == 'Live') { |
||
1478 | $stage = '_Live'; |
||
1479 | } |
||
1480 | |||
1481 | return $stage; |
||
1482 | } |
||
1483 | |||
1484 | /***************************************************** |
||
1485 | * STANDARD SS METHODS |
||
1486 | *****************************************************/ |
||
1487 | |||
1488 | /** |
||
1489 | * tells us if the current page is part of e-commerce. |
||
1490 | * |
||
1491 | * @return bool |
||
1492 | */ |
||
1493 | public function IsEcommercePage() |
||
1494 | { |
||
1495 | return true; |
||
1496 | } |
||
1497 | |||
1498 | public function onAfterWrite() |
||
1499 | { |
||
1500 | parent::onAfterWrite(); |
||
1501 | |||
1502 | if ($this->ImageID) { |
||
1503 | if ($normalImage = Image::get()->exclude(array('ClassName' => 'Product_Image'))->byID($this->ImageID)) { |
||
1504 | $normalImage = $normalImage->newClassInstance('Product_Image'); |
||
1505 | $normalImage->write(); |
||
1506 | } |
||
1507 | } |
||
1508 | } |
||
1509 | |||
1510 | function requireDefaultRecords() |
||
1511 | { |
||
1512 | parent::requireDefaultRecords(); |
||
1513 | $urlSegments = ProductGroup::get()->column('URLSegment'); |
||
1514 | foreach($urlSegments as $urlSegment) { |
||
1515 | $counts = array_count_values($urlSegments); |
||
1516 | $hasDuplicates = $counts[$urlSegment] > 1 ? true : false; |
||
1517 | if($hasDuplicates) { |
||
1518 | DB::alteration_message('found duplicates for '.$urlSegment, 'deleted'); |
||
1519 | $checkForDuplicatesURLSegments = ProductGroup::get() |
||
1520 | ->filter(array('URLSegment' => $urlSegment)); |
||
1521 | if($checkForDuplicatesURLSegments->count()){ |
||
1522 | $count = 0; |
||
1523 | foreach($checkForDuplicatesURLSegments as $productGroup) { |
||
1524 | if($count > 0) { |
||
1525 | $oldURLSegment = $productGroup->URLSegment; |
||
1526 | DB::alteration_message(' ... Correcting URLSegment for '.$productGroup->Title.' with ID: '.$productGroup->ID, 'deleted'); |
||
1527 | $productGroup->writeToStage('Stage'); |
||
1528 | $productGroup->publish('Stage', 'Live'); |
||
1529 | $newURLSegment = $productGroup->URLSegment; |
||
1530 | DB::alteration_message(' ... .... from '.$oldURLSegment.' to '.$newURLSegment, 'created'); |
||
1531 | } |
||
1532 | $count++; |
||
1533 | } |
||
1534 | } |
||
1535 | } |
||
1536 | } |
||
1537 | } |
||
1538 | |||
1539 | /***************************************************** |
||
1540 | * CACHING |
||
1541 | *****************************************************/ |
||
1542 | /** |
||
1543 | * |
||
1544 | * @return bool |
||
1545 | */ |
||
1546 | public function AllowCaching() |
||
1547 | { |
||
1548 | return $this->allowCaching; |
||
1549 | } |
||
1550 | |||
1551 | /** |
||
1552 | * keeps a cache of the common caching key element |
||
1553 | * @var string |
||
1554 | */ |
||
1555 | private static $_product_group_cache_key_cache = null; |
||
1556 | |||
1557 | /** |
||
1558 | * |
||
1559 | * @param string $name |
||
0 ignored issues
–
show
There is no parameter named
$name . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not.
Loading history...
|
|||
1560 | * @param string $filterKey |
||
0 ignored issues
–
show
There is no parameter named
$filterKey . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not.
Loading history...
|
|||
1561 | * |
||
1562 | * @return string |
||
1563 | */ |
||
1564 | public function cacheKey($cacheKey) |
||
1565 | { |
||
1566 | $cacheKey = $cacheKey.'_'.$this->ID; |
||
1567 | if (self::$_product_group_cache_key_cache === null) { |
||
1568 | self::$_product_group_cache_key_cache = "_PR_" |
||
1569 | .strtotime(Product::get()->max('LastEdited')). "_" |
||
1570 | .Product::get()->count(); |
||
1571 | self::$_product_group_cache_key_cache .= "PG_" |
||
1572 | .strtotime(ProductGroup::get()->max('LastEdited')). "_" |
||
1573 | .ProductGroup::get()->count(); |
||
1574 | if (class_exists('ProductVariation')) { |
||
1575 | self::$_product_group_cache_key_cache .= "PV_" |
||
1576 | .strtotime(ProductVariation::get()->max('LastEdited')). "_" |
||
1577 | .ProductVariation::get()->count(); |
||
1578 | } |
||
1579 | } |
||
1580 | $cacheKey .= self::$_product_group_cache_key_cache; |
||
1581 | |||
1582 | return $cacheKey; |
||
1583 | } |
||
1584 | |||
1585 | /** |
||
1586 | * @var Zend_Cache_Core |
||
1587 | */ |
||
1588 | protected $silverstripeCoreCache = null; |
||
1589 | |||
1590 | /** |
||
1591 | * Set the cache object to use when storing / retrieving partial cache blocks. |
||
1592 | * |
||
1593 | * @param Zend_Cache_Core $silverstripeCoreCache |
||
1594 | */ |
||
1595 | public function setSilverstripeCoreCache($silverstripeCoreCache) |
||
1596 | { |
||
1597 | $this->silverstripeCoreCache = $silverstripeCoreCache; |
||
1598 | } |
||
1599 | |||
1600 | /** |
||
1601 | * Get the cache object to use when storing / retrieving stuff in the Silverstripe Cache |
||
1602 | * |
||
1603 | * @return Zend_Cache_Core |
||
1604 | */ |
||
1605 | protected function getSilverstripeCoreCache() |
||
1606 | { |
||
1607 | return $this->silverstripeCoreCache ? $this->silverstripeCoreCache : SS_Cache::factory('EcomPG'); |
||
1608 | } |
||
1609 | |||
1610 | /** |
||
1611 | * saving an object to the. |
||
1612 | * |
||
1613 | * @param string $cacheKey |
||
1614 | * |
||
1615 | * @return mixed |
||
1616 | */ |
||
1617 | protected function retrieveObjectStore($cacheKey) |
||
1618 | { |
||
1619 | $cacheKey = $this->cacheKey($cacheKey); |
||
1620 | if ($this->AllowCaching()) { |
||
1621 | $cache = $this->getSilverstripeCoreCache(); |
||
1622 | $data = $cache->load($cacheKey); |
||
1623 | if (!$data) { |
||
1624 | return; |
||
1625 | } |
||
1626 | if (! $cache->getOption('automatic_serialization')) { |
||
1627 | $data = @unserialize($data); |
||
1628 | } |
||
1629 | return $data; |
||
1630 | } |
||
1631 | |||
1632 | return; |
||
1633 | } |
||
1634 | |||
1635 | /** |
||
1636 | * returns true when the data is saved... |
||
1637 | * |
||
1638 | * @param mixed $data |
||
1639 | * @param string $cacheKey - key under which the data is saved... |
||
1640 | * |
||
1641 | * @return bool |
||
1642 | */ |
||
1643 | protected function saveObjectStore($data, $cacheKey) |
||
1644 | { |
||
1645 | $cacheKey = $this->cacheKey($cacheKey); |
||
1646 | if ($this->AllowCaching()) { |
||
1647 | $cache = $this->getSilverstripeCoreCache(); |
||
1648 | if (! $cache->getOption('automatic_serialization')) { |
||
1649 | $data = serialize($data); |
||
1650 | } |
||
1651 | $cache->save($data, $cacheKey); |
||
1652 | return true; |
||
1653 | } |
||
1654 | |||
1655 | return false; |
||
1656 | } |
||
1657 | |||
1658 | public function SearchResultsSessionVariable($isForGroups = false) |
||
1659 | { |
||
1660 | $idString = '_'.$this->ID; |
||
1661 | if ($isForGroups) { |
||
1662 | return Config::inst()->get('ProductSearchForm', 'product_session_variable').$idString; |
||
1663 | } else { |
||
1664 | return Config::inst()->get('ProductSearchForm', 'product_group_session_variable').$idString; |
||
1665 | } |
||
1666 | } |
||
1667 | |||
1668 | /** |
||
1669 | * cache for result array. |
||
1670 | * |
||
1671 | * @var array |
||
1672 | */ |
||
1673 | private static $_result_array = array(); |
||
1674 | |||
1675 | /** |
||
1676 | * @return array |
||
1677 | */ |
||
1678 | public function searchResultsArrayFromSession() |
||
1679 | { |
||
1680 | if (! isset(self::$_result_array[$this->ID]) || self::$_result_array[$this->ID] === null) { |
||
1681 | self::$_result_array[$this->ID] = explode(',', Session::get($this->SearchResultsSessionVariable(false))); |
||
1682 | } |
||
1683 | if (! is_array(self::$_result_array[$this->ID]) || ! count(self::$_result_array[$this->ID])) { |
||
1684 | self::$_result_array[$this->ID] = array(0 => 0); |
||
1685 | } |
||
1686 | |||
1687 | return self::$_result_array[$this->ID]; |
||
1688 | } |
||
1689 | |||
1690 | public function getNumberOfProducts() |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a
Loading history...
|
|||
1691 | { |
||
1692 | return Product::get()->filter(array('ParentID' => $this->ID))->count(); |
||
1693 | } |
||
1694 | } |
||
1695 | |||
1696 | class ProductGroup_Controller extends Page_Controller |
||
1697 | { |
||
1698 | /** |
||
1699 | * standard SS variable. |
||
1700 | * |
||
1701 | * @var array |
||
1702 | */ |
||
1703 | private static $allowed_actions = array( |
||
0 ignored issues
–
show
|
|||
1704 | 'debug' => 'ADMIN', |
||
1705 | 'filterforgroup' => true, |
||
1706 | 'ProductSearchForm' => true, |
||
1707 | 'searchresults' => true, |
||
1708 | 'resetfilter' => true, |
||
1709 | ); |
||
1710 | |||
1711 | /** |
||
1712 | * The original Title of this page before filters, etc... |
||
1713 | * |
||
1714 | * @var string |
||
1715 | */ |
||
1716 | protected $originalTitle = ''; |
||
1717 | |||
1718 | /** |
||
1719 | * list of products that are going to be shown. |
||
1720 | * |
||
1721 | * @var DataList |
||
1722 | */ |
||
1723 | protected $products = null; |
||
1724 | |||
1725 | /** |
||
1726 | * Show all products on one page? |
||
1727 | * |
||
1728 | * @var bool |
||
1729 | */ |
||
1730 | protected $showFullList = false; |
||
1731 | |||
1732 | /** |
||
1733 | * The group filter that is applied to this page. |
||
1734 | * |
||
1735 | * @var ProductGroup |
||
1736 | */ |
||
1737 | protected $filterForGroupObject = null; |
||
1738 | |||
1739 | /** |
||
1740 | * Is this a product search? |
||
1741 | * |
||
1742 | * @var bool |
||
1743 | */ |
||
1744 | protected $isSearchResults = false; |
||
1745 | |||
1746 | /** |
||
1747 | * standard SS method. |
||
1748 | */ |
||
1749 | public function init() |
||
1750 | { |
||
1751 | parent::init(); |
||
1752 | $this->originalTitle = $this->Title; |
||
1753 | Requirements::themedCSS('ProductGroup', 'ecommerce'); |
||
1754 | Requirements::themedCSS('ProductGroupPopUp', 'ecommerce'); |
||
1755 | Requirements::javascript('ecommerce/javascript/EcomProducts.js'); |
||
1756 | //we save data from get variables... |
||
1757 | $this->saveUserPreferences(); |
||
1758 | } |
||
1759 | |||
1760 | /**************************************************** |
||
1761 | * ACTIONS |
||
1762 | /****************************************************/ |
||
1763 | |||
1764 | /** |
||
1765 | * standard selection of products. |
||
1766 | */ |
||
1767 | public function index() |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a
Loading history...
|
|||
1768 | { |
||
1769 | //set the filter and the sort... |
||
1770 | $this->addSecondaryTitle(); |
||
1771 | $this->products = $this->paginateList($this->ProductsShowable(null)); |
||
1772 | if ($this->returnAjaxifiedProductList()) { |
||
1773 | return $this->renderWith('AjaxProductList'); |
||
1774 | } |
||
1775 | return array(); |
||
1776 | } |
||
1777 | |||
1778 | /** |
||
1779 | * cross filter with another product group.. |
||
1780 | * |
||
1781 | * e.g. socks (current product group) for brand A or B (the secondary product group) |
||
1782 | * |
||
1783 | * @param HTTPRequest |
||
1784 | */ |
||
1785 | public function filterforgroup($request) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a
Loading history...
|
|||
1786 | { |
||
1787 | $this->resetfilter(); |
||
1788 | $otherGroupURLSegment = Convert::raw2sql($request->param('ID')); |
||
1789 | $arrayOfIDs = array(0 => 0); |
||
1790 | if ($otherGroupURLSegment) { |
||
1791 | $otherProductGroup = DataObject::get_one( |
||
1792 | 'ProductGroup', |
||
1793 | array('URLSegment' => $otherGroupURLSegment) |
||
1794 | ); |
||
1795 | if ($otherProductGroup) { |
||
1796 | $this->filterForGroupObject = $otherProductGroup; |
||
1797 | $arrayOfIDs = $otherProductGroup->currentInitialProductsAsCachedArray($this->getMyUserPreferencesDefault('FILTER')); |
||
1798 | } |
||
1799 | } |
||
1800 | $this->addSecondaryTitle(); |
||
1801 | $this->products = $this->paginateList($this->ProductsShowable(array('ID' => $arrayOfIDs))); |
||
1802 | if ($this->returnAjaxifiedProductList()) { |
||
1803 | return $this->renderWith('AjaxProductList'); |
||
1804 | } |
||
1805 | |||
1806 | return array(); |
||
1807 | } |
||
1808 | |||
1809 | /** |
||
1810 | * get the search results. |
||
1811 | * |
||
1812 | * @param HTTPRequest |
||
1813 | */ |
||
1814 | public function searchresults($request) |
||
1815 | { |
||
1816 | $this->resetfilter(); |
||
1817 | $this->isSearchResults = true; |
||
1818 | //reset filter and sort |
||
1819 | $resultArray = $this->searchResultsArrayFromSession(); |
||
1820 | if (!$resultArray || !count($resultArray)) { |
||
1821 | $resultArray = array(0 => 0); |
||
1822 | } |
||
1823 | $defaultKeySort = $this->getMyUserPreferencesDefault('SORT'); |
||
1824 | $myKeySort = $this->getCurrentUserPreferences('SORT'); |
||
1825 | $searchArray = null; |
||
1826 | if ($defaultKeySort == $myKeySort) { |
||
1827 | $searchArray = $resultArray; |
||
1828 | } |
||
1829 | $this->addSecondaryTitle(); |
||
1830 | $this->products = $this->paginateList($this->ProductsShowable(array('ID' => $resultArray), $searchArray)); |
||
1831 | |||
1832 | return array(); |
||
1833 | } |
||
1834 | |||
1835 | /** |
||
1836 | * resets the filter only. |
||
1837 | */ |
||
1838 | public function resetfilter() |
||
1839 | { |
||
1840 | $defaultKey = $this->getMyUserPreferencesDefault('FILTER'); |
||
1841 | $filterGetVariable = $this->getSortFilterDisplayNames('FILTER', 'getVariable'); |
||
1842 | $this->saveUserPreferences( |
||
1843 | array( |
||
1844 | $filterGetVariable => $defaultKey, |
||
1845 | ) |
||
1846 | ); |
||
1847 | |||
1848 | return array(); |
||
1849 | } |
||
1850 | |||
1851 | /**************************************************** |
||
1852 | * TEMPLATE METHODS PRODUCTS |
||
1853 | /****************************************************/ |
||
1854 | |||
1855 | /** |
||
1856 | * Return the products for this group. |
||
1857 | * This is the call that is made from the template... |
||
1858 | * The actual final products being shown. |
||
1859 | * |
||
1860 | * @return PaginatedList |
||
0 ignored issues
–
show
|
|||
1861 | **/ |
||
1862 | public function Products() |
||
1863 | { |
||
1864 | //IMPORTANT! |
||
1865 | //two universal actions! |
||
1866 | $this->addSecondaryTitle(); |
||
1867 | $this->cachingRelatedJavascript(); |
||
1868 | |||
1869 | //save products to session for later use |
||
1870 | $stringOfIDs = ''; |
||
1871 | $array = $this->getProductsThatCanBePurchasedArray(); |
||
1872 | if (is_array($array)) { |
||
1873 | $stringOfIDs = implode(',', $array); |
||
1874 | } |
||
1875 | //save list for future use |
||
1876 | Session::set(EcommerceConfig::get('ProductGroup', 'session_name_for_product_array'), $stringOfIDs); |
||
1877 | |||
1878 | return $this->products; |
||
1879 | } |
||
1880 | |||
1881 | /** |
||
1882 | * you can overload this function of ProductGroup Extensions. |
||
1883 | * |
||
1884 | * @return bool |
||
1885 | */ |
||
1886 | protected function returnAjaxifiedProductList() |
||
1887 | { |
||
1888 | return Director::is_ajax() ? true : false; |
||
1889 | } |
||
1890 | |||
1891 | /** |
||
1892 | * is the product list cache-able? |
||
1893 | * |
||
1894 | * @return bool |
||
1895 | */ |
||
1896 | public function ProductGroupListAreCacheable() |
||
1897 | { |
||
1898 | if ($this->productListsHTMLCanBeCached()) { |
||
1899 | //exception 1 |
||
1900 | if ($this->IsSearchResults()) { |
||
1901 | return false; |
||
1902 | } |
||
1903 | //exception 2 |
||
1904 | $currentOrder = ShoppingCart::current_order(); |
||
1905 | if ($currentOrder->getHasAlternativeCurrency()) { |
||
0 ignored issues
–
show
|
|||
1906 | return false; |
||
1907 | } |
||
1908 | //can be cached... |
||
1909 | return true; |
||
1910 | } |
||
1911 | |||
1912 | return false; |
||
1913 | } |
||
1914 | |||
1915 | /** |
||
1916 | * is the product list ajaxified. |
||
1917 | * |
||
1918 | * @return bool |
||
1919 | */ |
||
1920 | public function ProductGroupListAreAjaxified() |
||
1921 | { |
||
1922 | return $this->IsSearchResults() ? false : true; |
||
1923 | } |
||
1924 | |||
1925 | /** |
||
1926 | * Unique caching key for the product list... |
||
1927 | * |
||
1928 | * @return string | Null |
||
0 ignored issues
–
show
|
|||
1929 | */ |
||
1930 | public function ProductGroupListCachingKey() |
||
0 ignored issues
–
show
ProductGroupListCachingKey uses the super-global variable $_GET which is generally not recommended.
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: // Bad
class Router
{
public function generate($path)
{
return $_SERVER['HOST'].$path;
}
}
// Better
class Router
{
private $host;
public function __construct($host)
{
$this->host = $host;
}
public function generate($path)
{
return $this->host.$path;
}
}
class Controller
{
public function myAction(Request $request)
{
// Instead of
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Better (assuming you use the Symfony2 request)
$page = $request->query->get('page', 1);
}
}
Loading history...
|
|||
1931 | { |
||
1932 | if ($this->ProductGroupListAreCacheable()) { |
||
1933 | $displayKey = $this->getCurrentUserPreferences('DISPLAY'); |
||
1934 | $filterKey = $this->getCurrentUserPreferences('FILTER'); |
||
1935 | $filterForGroupKey = $this->filterForGroupObject ? $this->filterForGroupObject->ID : 0; |
||
1936 | $sortKey = $this->getCurrentUserPreferences('SORT'); |
||
1937 | $pageStart = isset($_GET['start']) ? intval($_GET['start']) : 0; |
||
1938 | $isFullList = $this->IsShowFullList() ? 'Y' : 'N'; |
||
1939 | |||
1940 | $this->cacheKey( |
||
1941 | implode( |
||
1942 | '_', |
||
1943 | array( |
||
1944 | $displayKey, |
||
1945 | $filterKey, |
||
1946 | $filterForGroupKey, |
||
1947 | $sortKey, |
||
1948 | $pageStart, |
||
1949 | $isFullList, |
||
1950 | ) |
||
1951 | ) |
||
1952 | ); |
||
1953 | } |
||
1954 | |||
1955 | return; |
||
1956 | } |
||
1957 | |||
1958 | /** |
||
1959 | * adds Javascript to the page to make it work when products are cached. |
||
1960 | */ |
||
1961 | public function CachingRelatedJavascript() |
||
1962 | { |
||
1963 | if ($this->ProductGroupListAreAjaxified()) { |
||
1964 | Requirements::customScript(" |
||
1965 | if(typeof EcomCartOptions === 'undefined') { |
||
1966 | var EcomCartOptions = {}; |
||
1967 | } |
||
1968 | EcomCartOptions.ajaxifyProductList = true; |
||
1969 | EcomCartOptions.ajaxifiedListHolderSelector = '#".$this->AjaxDefinitions()->ProductListHolderID()."'; |
||
1970 | EcomCartOptions.ajaxifiedListAdjusterSelectors = '.".$this->AjaxDefinitions()->ProductListAjaxifiedLinkClassName()."'; |
||
1971 | EcomCartOptions.hiddenPageTitleID = '#".$this->AjaxDefinitions()->HiddenPageTitleID()."'; |
||
1972 | ", |
||
1973 | 'cachingRelatedJavascript_AJAXlist' |
||
1974 | ); |
||
1975 | } else { |
||
1976 | Requirements::customScript(" |
||
1977 | if(typeof EcomCartOptions === 'undefined') { |
||
1978 | var EcomCartOptions = {}; |
||
1979 | } |
||
1980 | EcomCartOptions.ajaxifyProductList = false; |
||
1981 | ", |
||
1982 | 'cachingRelatedJavascript_AJAXlist' |
||
1983 | ); |
||
1984 | } |
||
1985 | $currentOrder = ShoppingCart::current_order(); |
||
1986 | if ($currentOrder->TotalItems(true)) { |
||
1987 | $responseClass = EcommerceConfig::get('ShoppingCart', 'response_class'); |
||
1988 | $obj = new $responseClass(); |
||
1989 | $obj->setIncludeHeaders(false); |
||
1990 | $json = $obj->ReturnCartData(); |
||
1991 | Requirements::customScript(" |
||
1992 | if(typeof EcomCartOptions === 'undefined') { |
||
1993 | var EcomCartOptions = {}; |
||
1994 | } |
||
1995 | EcomCartOptions.initialData= ".$json."; |
||
1996 | ", |
||
1997 | 'cachingRelatedJavascript_JSON' |
||
1998 | ); |
||
1999 | } |
||
2000 | } |
||
2001 | |||
2002 | /** |
||
2003 | * you can overload this function of ProductGroup Extensions. |
||
2004 | * |
||
2005 | * @return bool |
||
2006 | */ |
||
2007 | protected function productListsHTMLCanBeCached() |
||
2008 | { |
||
2009 | return Config::inst()->get('ProductGroup', 'actively_check_for_can_purchase') ? false : true; |
||
2010 | } |
||
2011 | |||
2012 | /***************************************************** |
||
2013 | * DATALIST: totals, number per page, etc.. |
||
2014 | *****************************************************/ |
||
2015 | |||
2016 | /** |
||
2017 | * returns the total numer of products (before pagination). |
||
2018 | * |
||
2019 | * @return bool |
||
2020 | **/ |
||
2021 | public function TotalCountGreaterThanOne($greaterThan = 1) |
||
2022 | { |
||
2023 | return $this->TotalCount() > $greaterThan; |
||
2024 | } |
||
2025 | |||
2026 | /** |
||
2027 | * have the ProductsShowable been limited. |
||
2028 | * |
||
2029 | * @return bool |
||
2030 | **/ |
||
2031 | public function TotalCountGreaterThanMax() |
||
2032 | { |
||
2033 | return $this->RawCount() > $this->TotalCount(); |
||
2034 | } |
||
2035 | |||
2036 | /**************************************************** |
||
2037 | * TEMPLATE METHODS MENUS AND SIDEBARS |
||
2038 | /****************************************************/ |
||
2039 | |||
2040 | /** |
||
2041 | * title without additions. |
||
2042 | * |
||
2043 | * @return string |
||
2044 | */ |
||
2045 | public function OriginalTitle() |
||
2046 | { |
||
2047 | return $this->originalTitle; |
||
2048 | } |
||
2049 | /** |
||
2050 | * This method can be extended to show products in the side bar. |
||
2051 | */ |
||
2052 | public function SidebarProducts() |
||
2053 | { |
||
2054 | return; |
||
2055 | } |
||
2056 | |||
2057 | /** |
||
2058 | * returns child product groups for use in |
||
2059 | * 'in this section'. For example the vegetable Product Group |
||
2060 | * May have listed here: Carrot, Cabbage, etc... |
||
2061 | * |
||
2062 | * @return ArrayList (ProductGroups) |
||
2063 | */ |
||
2064 | public function MenuChildGroups() |
||
2065 | { |
||
2066 | return $this->ChildGroups(2, '"ShowInMenus" = 1'); |
||
2067 | } |
||
2068 | |||
2069 | /** |
||
2070 | * After a search is conducted you may end up with a bunch |
||
2071 | * of recommended product groups. They will be returned here... |
||
2072 | * We sort the list in the order that it is provided. |
||
2073 | * |
||
2074 | * @return DataList | Null (ProductGroups) |
||
2075 | */ |
||
2076 | public function SearchResultsChildGroups() |
||
2077 | { |
||
2078 | $groupArray = explode(',', Session::get($this->SearchResultsSessionVariable($isForGroup = true))); |
||
2079 | if (is_array($groupArray) && count($groupArray)) { |
||
2080 | $sortStatement = $this->createSortStatementFromIDArray($groupArray, 'ProductGroup'); |
||
2081 | |||
2082 | return ProductGroup::get()->filter(array('ID' => $groupArray, 'ShowInSearch' => 1))->sort($sortStatement); |
||
2083 | } |
||
2084 | |||
2085 | return; |
||
2086 | } |
||
2087 | |||
2088 | /**************************************************** |
||
2089 | * Search Form Related controllers |
||
2090 | /****************************************************/ |
||
2091 | |||
2092 | /** |
||
2093 | * returns a search form to search current products. |
||
2094 | * |
||
2095 | * @return ProductSearchForm object |
||
2096 | */ |
||
2097 | public function ProductSearchForm() |
||
2098 | { |
||
2099 | $onlySearchTitle = $this->originalTitle; |
||
2100 | if ($this->dataRecord instanceof ProductGroupSearchPage) { |
||
2101 | if ($this->HasSearchResults()) { |
||
2102 | $onlySearchTitle = 'Last Search Results'; |
||
2103 | } |
||
2104 | } |
||
2105 | $form = ProductSearchForm::create( |
||
2106 | $this, |
||
2107 | 'ProductSearchForm', |
||
2108 | $onlySearchTitle, |
||
2109 | $this->currentInitialProducts(null, $this->getMyUserPreferencesDefault('FILTER')) |
||
2110 | ); |
||
2111 | $filterGetVariable = $this->getSortFilterDisplayNames('FILTER', 'getVariable'); |
||
2112 | $sortGetVariable = $this->getSortFilterDisplayNames('SORT', 'getVariable'); |
||
2113 | $additionalGetParameters = $filterGetVariable.'='.$this->getMyUserPreferencesDefault('FILTER').'&'. |
||
2114 | $sortGetVariable.'='.$this->getMyUserPreferencesDefault('SORT'); |
||
2115 | $form->setAdditionalGetParameters($additionalGetParameters); |
||
2116 | |||
2117 | return $form; |
||
2118 | } |
||
2119 | |||
2120 | /** |
||
2121 | * Does this page have any search results? |
||
2122 | * If search was carried out without returns |
||
2123 | * then it returns zero (false). |
||
2124 | * |
||
2125 | * @return int | false |
||
2126 | */ |
||
2127 | public function HasSearchResults() |
||
2128 | { |
||
2129 | $resultArray = $this->searchResultsArrayFromSession(); |
||
2130 | if ($resultArray) { |
||
2131 | $count = count($resultArray) - 1; |
||
2132 | |||
2133 | return $count ? $count : 0; |
||
2134 | } |
||
2135 | |||
2136 | return 0; |
||
2137 | } |
||
2138 | |||
2139 | /** |
||
2140 | * Should the product search form be shown immediately? |
||
2141 | * |
||
2142 | * @return bool |
||
2143 | */ |
||
2144 | public function ShowSearchFormImmediately() |
||
2145 | { |
||
2146 | if ($this->IsSearchResults()) { |
||
2147 | return true; |
||
2148 | } |
||
2149 | if ((!$this->products) || ($this->products && $this->products->count())) { |
||
0 ignored issues
–
show
|
|||
2150 | return false; |
||
2151 | } |
||
2152 | |||
2153 | return true; |
||
2154 | } |
||
2155 | |||
2156 | /** |
||
2157 | * Show a search form on this page? |
||
2158 | * |
||
2159 | * @return bool |
||
2160 | */ |
||
2161 | public function ShowSearchFormAtAll() |
||
2162 | { |
||
2163 | return true; |
||
2164 | } |
||
2165 | |||
2166 | /** |
||
2167 | * Is the current page a display of search results. |
||
2168 | * |
||
2169 | * This does not mean that something is actively being search for, |
||
2170 | * it could also be just "showing the search results" |
||
2171 | * |
||
2172 | * @return bool |
||
2173 | */ |
||
2174 | public function IsSearchResults() |
||
2175 | { |
||
2176 | return $this->isSearchResults; |
||
2177 | } |
||
2178 | |||
2179 | /** |
||
2180 | * Is there something actively being searched for? |
||
2181 | * |
||
2182 | * This is different from IsSearchResults. |
||
2183 | * |
||
2184 | * @return bool |
||
0 ignored issues
–
show
|
|||
2185 | */ |
||
2186 | public function ActiveSearchTerm() |
||
2187 | { |
||
2188 | $data = Session::get(Config::inst()->get('ProductSearchForm', 'form_data_session_variable')); |
||
2189 | if (!empty($data['Keyword'])) { |
||
2190 | return $this->IsSearchResults(); |
||
2191 | } |
||
2192 | } |
||
2193 | |||
2194 | /**************************************************** |
||
2195 | * Filter / Sort / Display related controllers |
||
2196 | /****************************************************/ |
||
2197 | |||
2198 | /** |
||
2199 | * Do we show all products on one page? |
||
2200 | * |
||
2201 | * @return bool |
||
2202 | */ |
||
2203 | public function ShowFiltersAndDisplayLinks() |
||
2204 | { |
||
2205 | if ($this->TotalCountGreaterThanOne()) { |
||
2206 | if ($this->HasFilters()) { |
||
2207 | return true; |
||
2208 | } |
||
2209 | if ($this->DisplayLinks()) { |
||
2210 | return true; |
||
2211 | } |
||
2212 | } |
||
2213 | |||
2214 | return false; |
||
2215 | } |
||
2216 | |||
2217 | /** |
||
2218 | * Do we show the sort links. |
||
2219 | * |
||
2220 | * A bit arbitrary to say three, |
||
2221 | * but there is not much point to sort three or less products |
||
2222 | * |
||
2223 | * @return bool |
||
2224 | */ |
||
2225 | public function ShowSortLinks($minimumCount = 3) |
||
2226 | { |
||
2227 | if ($this->TotalCountGreaterThanOne($minimumCount)) { |
||
0 ignored issues
–
show
|
|||
2228 | return true; |
||
2229 | } |
||
2230 | |||
2231 | return false; |
||
2232 | } |
||
2233 | |||
2234 | /** |
||
2235 | * Is there a special filter operating at the moment? |
||
2236 | * Is the current filter the default one (return inverse!)? |
||
2237 | * |
||
2238 | * @return bool |
||
2239 | */ |
||
2240 | public function HasFilter() |
||
2241 | { |
||
2242 | return $this->getCurrentUserPreferences('FILTER') != $this->getMyUserPreferencesDefault('FILTER') |
||
2243 | || $this->filterForGroupObject; |
||
2244 | } |
||
2245 | |||
2246 | /** |
||
2247 | * Is there a special sort operating at the moment? |
||
2248 | * Is the current sort the default one (return inverse!)? |
||
2249 | * |
||
2250 | * @return bool |
||
0 ignored issues
–
show
|
|||
2251 | */ |
||
2252 | public function HasSort() |
||
2253 | { |
||
2254 | $sort = $this->getCurrentUserPreferences('SORT'); |
||
2255 | if ($sort != $this->getMyUserPreferencesDefault('SORT')) { |
||
2256 | return true; |
||
2257 | } |
||
2258 | } |
||
2259 | |||
2260 | /** |
||
2261 | * @return boolean |
||
2262 | */ |
||
2263 | public function HasFilterOrSort() |
||
2264 | { |
||
2265 | return $this->HasFilter() || $this->HasSort(); |
||
2266 | } |
||
2267 | |||
2268 | /** |
||
2269 | * @return boolean |
||
2270 | */ |
||
2271 | public function HasFilterOrSortFullList() |
||
2272 | { |
||
2273 | return $this->HasFilterOrSort() || $this->IsShowFullList(); |
||
2274 | } |
||
2275 | |||
2276 | /** |
||
2277 | * are filters available? |
||
2278 | * we check one at the time so that we do the least |
||
2279 | * amount of DB queries. |
||
2280 | * |
||
2281 | * @return bool |
||
2282 | */ |
||
2283 | public function HasFilters() |
||
2284 | { |
||
2285 | $countFilters = $this->FilterLinks()->count(); |
||
2286 | if ($countFilters > 1) { |
||
2287 | return true; |
||
2288 | } |
||
2289 | $countGroupFilters = $this->ProductGroupFilterLinks()->count(); |
||
2290 | if ($countGroupFilters > 1) { |
||
2291 | return true; |
||
2292 | } |
||
2293 | if ($countFilters + $countGroupFilters > 1) { |
||
0 ignored issues
–
show
|
|||
2294 | return true; |
||
2295 | } |
||
2296 | |||
2297 | return false; |
||
2298 | } |
||
2299 | |||
2300 | /** |
||
2301 | * Do we show all products on one page? |
||
2302 | * |
||
2303 | * @return bool |
||
2304 | */ |
||
2305 | public function IsShowFullList() |
||
2306 | { |
||
2307 | return $this->showFullList; |
||
2308 | } |
||
2309 | |||
2310 | /** |
||
2311 | * returns the current filter applied to the list |
||
2312 | * in a human readable string. |
||
2313 | * |
||
2314 | * @return string |
||
2315 | */ |
||
2316 | public function CurrentDisplayTitle() |
||
2317 | { |
||
2318 | $displayKey = $this->getCurrentUserPreferences('DISPLAY'); |
||
2319 | if ($displayKey != $this->getMyUserPreferencesDefault('DISPLAY')) { |
||
2320 | return $this->getUserPreferencesTitle('DISPLAY', $displayKey); |
||
2321 | } |
||
2322 | } |
||
2323 | |||
2324 | /** |
||
2325 | * returns the current filter applied to the list |
||
2326 | * in a human readable string. |
||
2327 | * |
||
2328 | * @return string |
||
0 ignored issues
–
show
|
|||
2329 | */ |
||
2330 | public function CurrentFilterTitle() |
||
2331 | { |
||
2332 | $filterKey = $this->getCurrentUserPreferences('FILTER'); |
||
2333 | $filters = array(); |
||
2334 | if ($filterKey != $this->getMyUserPreferencesDefault('FILTER')) { |
||
2335 | $filters[] = $this->getUserPreferencesTitle('FILTER', $filterKey); |
||
2336 | } |
||
2337 | if ($this->filterForGroupObject) { |
||
2338 | $filters[] = $this->filterForGroupObject->MenuTitle; |
||
2339 | } |
||
2340 | if (count($filters)) { |
||
2341 | return implode(', ', $filters); |
||
2342 | } |
||
2343 | } |
||
2344 | |||
2345 | /** |
||
2346 | * returns the current sort applied to the list |
||
2347 | * in a human readable string. |
||
2348 | * |
||
2349 | * @return string |
||
2350 | */ |
||
2351 | public function CurrentSortTitle() |
||
2352 | { |
||
2353 | $sortKey = $this->getCurrentUserPreferences('SORT'); |
||
2354 | if ($sortKey != $this->getMyUserPreferencesDefault('SORT')) { |
||
2355 | return $this->getUserPreferencesTitle('SORT', $sortKey); |
||
2356 | } |
||
2357 | } |
||
2358 | |||
2359 | /** |
||
2360 | * short-cut for getMyUserPreferencesDefault("DISPLAY") |
||
2361 | * for use in templtes. |
||
2362 | * |
||
2363 | * @return string - key |
||
2364 | */ |
||
2365 | public function MyDefaultDisplayStyle() |
||
2366 | { |
||
2367 | return $this->getMyUserPreferencesDefault('DISPLAY'); |
||
2368 | } |
||
2369 | |||
2370 | /** |
||
2371 | * Number of entries per page limited by total number of pages available... |
||
2372 | * |
||
2373 | * @return int |
||
2374 | */ |
||
2375 | public function MaxNumberOfProductsPerPage() |
||
2376 | { |
||
2377 | return $this->MyNumberOfProductsPerPage() > $this->TotalCount() ? $this->TotalCount() : $this->MyNumberOfProductsPerPage(); |
||
2378 | } |
||
2379 | |||
2380 | /**************************************************** |
||
2381 | * TEMPLATE METHODS FILTER LINK |
||
2382 | /****************************************************/ |
||
2383 | |||
2384 | /** |
||
2385 | * Provides a ArrayList of links for filters products. |
||
2386 | * |
||
2387 | * @return ArrayList( ArrayData(Name, Link, SelectKey, Current (boolean), LinkingMode)) |
||
0 ignored issues
–
show
The doc-type
ArrayList( could not be parsed: Expected "|" or "end of type", but got "(" at position 9. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.
Loading history...
|
|||
2388 | */ |
||
2389 | public function FilterLinks() |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a
Loading history...
|
|||
2390 | { |
||
2391 | $cacheKey = 'FilterLinks_'.($this->filterForGroupObject ? $this->filterForGroupObject->ID : 0); |
||
2392 | if ($list = $this->retrieveObjectStore($cacheKey)) { |
||
2393 | //do nothing |
||
2394 | } else { |
||
2395 | $list = $this->userPreferencesLinks('FILTER'); |
||
2396 | foreach ($list as $obj) { |
||
0 ignored issues
–
show
The expression
$list of type null|this<ProductGroup_Controller> is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
Loading history...
|
|||
2397 | $key = $obj->SelectKey; |
||
2398 | if ($key != $this->getMyUserPreferencesDefault('FILTER')) { |
||
2399 | $count = count($this->currentInitialProductsAsCachedArray($key)); |
||
2400 | if ($count == 0) { |
||
2401 | $list->remove($obj); |
||
2402 | } else { |
||
2403 | $obj->Count = $count; |
||
2404 | } |
||
2405 | } |
||
2406 | } |
||
2407 | $this->saveObjectStore($list, $cacheKey); |
||
2408 | } |
||
2409 | $selectedItem = $this->getCurrentUserPreferences('FILTER'); |
||
2410 | foreach ($list as $obj) { |
||
2411 | $canHaveCurrent = true; |
||
2412 | if ($this->filterForGroupObject) { |
||
2413 | $canHaveCurrent = false; |
||
2414 | } |
||
2415 | $obj->Current = $selectedItem == $obj->SelectKey && $canHaveCurrent ? true : false; |
||
2416 | $obj->LinkingMode = $obj->Current ? 'current' : 'link'; |
||
2417 | $obj->Ajaxify = true; |
||
2418 | } |
||
2419 | |||
2420 | return $list; |
||
2421 | } |
||
2422 | |||
2423 | /** |
||
2424 | * returns a list of items (with links). |
||
2425 | * |
||
2426 | * @return ArrayList( ArrayData(Name, FilterLink, SelectKey, Current (boolean), LinkingMode)) |
||
0 ignored issues
–
show
The doc-type
ArrayList( could not be parsed: Expected "|" or "end of type", but got "(" at position 9. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.
Loading history...
|
|||
2427 | */ |
||
2428 | public function ProductGroupFilterLinks() |
||
2429 | { |
||
2430 | if ($array = $this->retrieveObjectStore('ProductGroupFilterLinks')) { |
||
2431 | //do nothing |
||
2432 | } else { |
||
2433 | $arrayOfItems = array(); |
||
2434 | |||
2435 | $baseArray = $this->currentInitialProductsAsCachedArray($this->getMyUserPreferencesDefault('FILTER')); |
||
2436 | |||
2437 | //also show |
||
2438 | $items = $this->ProductGroupsFromAlsoShowProducts(); |
||
2439 | $arrayOfItems = array_merge($arrayOfItems, $this->productGroupFilterLinksCount($items, $baseArray, true)); |
||
2440 | //also show inverse |
||
2441 | $items = $this->ProductGroupsFromAlsoShowProductsInverse(); |
||
2442 | $arrayOfItems = array_merge($arrayOfItems, $this->productGroupFilterLinksCount($items, $baseArray, true)); |
||
2443 | |||
2444 | //parent groups |
||
2445 | $items = $this->ProductGroupsParentGroups(); |
||
2446 | $arrayOfItems = array_merge($arrayOfItems, $this->productGroupFilterLinksCount($items, $baseArray, true)); |
||
2447 | |||
2448 | //child groups |
||
2449 | $items = $this->MenuChildGroups(); |
||
2450 | $arrayOfItems = array_merge($arrayOfItems, $this->productGroupFilterLinksCount($items, $baseArray, true)); |
||
2451 | |||
2452 | ksort($arrayOfItems); |
||
2453 | $array = array(); |
||
2454 | foreach ($arrayOfItems as $arrayOfItem) { |
||
2455 | $array[] = $this->makeArrayItem($arrayOfItem); |
||
2456 | } |
||
2457 | $this->saveObjectStore($array, 'ProductGroupFilterLinks'); |
||
2458 | } |
||
2459 | $arrayList = ArrayList::create(); |
||
2460 | foreach ($array as $item) { |
||
2461 | $arrayList->push(ArrayData::create($item)); |
||
2462 | } |
||
2463 | return $arrayList; |
||
2464 | } |
||
2465 | |||
2466 | /** |
||
2467 | * counts the total number in the combination.... |
||
2468 | * |
||
2469 | * @param DataList $items - list of |
||
2470 | * @param Arary $baseArray - list of products on the current page |
||
2471 | * |
||
2472 | * @return array |
||
2473 | */ |
||
2474 | protected function productGroupFilterLinksCount($items, $baseArray, $ajaxify = true) |
||
2475 | { |
||
2476 | $array = array(); |
||
2477 | if ($items && $items->count()) { |
||
2478 | foreach ($items as $item) { |
||
2479 | $arrayOfIDs = $item->currentInitialProductsAsCachedArray($this->getMyUserPreferencesDefault('FILTER')); |
||
2480 | $newArray = array_intersect_key( |
||
2481 | $arrayOfIDs, |
||
2482 | $baseArray |
||
2483 | ); |
||
2484 | $count = count($newArray); |
||
2485 | if ($count) { |
||
2486 | $array[$item->Title] = array( |
||
2487 | 'Item' => $item, |
||
2488 | 'Count' => $count, |
||
2489 | 'Ajaxify' => $ajaxify, |
||
2490 | ); |
||
2491 | } |
||
2492 | } |
||
2493 | } |
||
2494 | |||
2495 | return $array; |
||
2496 | } |
||
2497 | |||
2498 | /** |
||
2499 | * @param array itemInArray (Item, Count, UserFilterAction) |
||
2500 | * |
||
2501 | * @return ArrayData |
||
0 ignored issues
–
show
|
|||
2502 | */ |
||
2503 | protected function makeArrayItem($itemInArray) |
||
2504 | { |
||
2505 | $item = $itemInArray['Item']; |
||
2506 | $count = $itemInArray['Count']; |
||
2507 | $ajaxify = $itemInArray['Ajaxify']; |
||
2508 | $filterForGroupObjectID = $this->filterForGroupObject ? $this->filterForGroupObject->ID : 0; |
||
2509 | $isCurrent = $item->ID == $filterForGroupObjectID; |
||
2510 | if ($ajaxify) { |
||
2511 | $link = $this->Link('filterforgroup/'.$item->URLSegment); |
||
2512 | } else { |
||
2513 | $link = $item->Link(); |
||
2514 | } |
||
2515 | return array( |
||
2516 | 'Title' => $item->Title, |
||
2517 | 'Count' => $count, |
||
2518 | 'SelectKey' => $item->URLSegment, |
||
2519 | 'Current' => $isCurrent ? true : false, |
||
2520 | 'MyLinkingMode' => $isCurrent ? 'current' : 'link', |
||
2521 | 'FilterLink' => $link, |
||
2522 | 'Ajaxify' => $ajaxify ? true : false, |
||
2523 | ); |
||
2524 | } |
||
2525 | |||
2526 | /** |
||
2527 | * Provides a ArrayList of links for sorting products. |
||
2528 | */ |
||
2529 | public function SortLinks() |
||
2530 | { |
||
2531 | $list = $this->userPreferencesLinks('SORT'); |
||
2532 | $selectedItem = $this->getCurrentUserPreferences('SORT'); |
||
2533 | if ($list) { |
||
2534 | foreach ($list as $obj) { |
||
2535 | $obj->Current = $selectedItem == $obj->SelectKey ? true : false; |
||
2536 | $obj->LinkingMode = $obj->Current ? 'current' : 'link'; |
||
2537 | $obj->Ajaxify = true; |
||
2538 | } |
||
2539 | |||
2540 | return $list; |
||
2541 | } |
||
2542 | } |
||
2543 | |||
2544 | /** |
||
2545 | * Provides a ArrayList for displaying display links. |
||
2546 | */ |
||
2547 | public function DisplayLinks() |
||
2548 | { |
||
2549 | $list = $this->userPreferencesLinks('DISPLAY'); |
||
2550 | $selectedItem = $this->getCurrentUserPreferences('DISPLAY'); |
||
2551 | if ($list) { |
||
2552 | foreach ($list as $obj) { |
||
2553 | $obj->Current = $selectedItem == $obj->SelectKey ? true : false; |
||
2554 | $obj->LinkingMode = $obj->Current ? 'current' : 'link'; |
||
2555 | $obj->Ajaxify = true; |
||
2556 | } |
||
2557 | |||
2558 | return $list; |
||
2559 | } |
||
2560 | } |
||
2561 | |||
2562 | /** |
||
2563 | * The link that Google et al. need to index. |
||
2564 | * @return string |
||
2565 | */ |
||
2566 | public function CanonicalLink() |
||
2567 | { |
||
2568 | $link = $this->ListAllLink(); |
||
2569 | $this->extend('UpdateCanonicalLink', $link); |
||
2570 | |||
2571 | return $link; |
||
2572 | } |
||
2573 | |||
2574 | |||
2575 | /** |
||
2576 | * Link that returns a list of all the products |
||
2577 | * for this product group as a simple list. |
||
2578 | * |
||
2579 | * @return string |
||
2580 | */ |
||
2581 | public function ListAllLink() |
||
2582 | { |
||
2583 | if ($this->filterForGroupObject) { |
||
2584 | return $this->Link('filterforgroup/'.$this->filterForGroupObject->URLSegment).'?showfulllist=1'; |
||
2585 | } else { |
||
2586 | return $this->Link().'?showfulllist=1'; |
||
2587 | } |
||
2588 | } |
||
2589 | |||
2590 | /** |
||
2591 | * Link that returns a list of all the products |
||
2592 | * for this product group as a simple list. |
||
2593 | * |
||
2594 | * @return string |
||
2595 | */ |
||
2596 | public function ListAFewLink() |
||
2597 | { |
||
2598 | return str_replace('?showfulllist=1', '', $this->ListAllLink()); |
||
2599 | } |
||
2600 | |||
2601 | /** |
||
2602 | * Link that returns a list of all the products |
||
2603 | * for this product group as a simple list. |
||
2604 | * |
||
2605 | * It resets everything - not just filter.... |
||
2606 | * |
||
2607 | * @return string |
||
2608 | */ |
||
2609 | public function ResetPreferencesLink($escapedAmpersands = true) |
||
2610 | { |
||
2611 | $ampersand = '&'; |
||
2612 | if ($escapedAmpersands) { |
||
2613 | $ampersand = '&'; |
||
2614 | } |
||
2615 | $getVariableNameFilter = $this->getSortFilterDisplayNames('FILTER', 'getVariable'); |
||
2616 | $getVariableNameSort = $this->getSortFilterDisplayNames('SORT', 'getVariable'); |
||
2617 | |||
2618 | return $this->Link().'?'. |
||
2619 | $getVariableNameFilter.'='.$this->getMyUserPreferencesDefault('FILTER').$ampersand. |
||
2620 | $getVariableNameSort.'='.$this->getMyUserPreferencesDefault('SORT').$ampersand. |
||
2621 | 'reload=1'; |
||
2622 | } |
||
2623 | |||
2624 | /** |
||
2625 | * Link to the search results. |
||
2626 | * |
||
2627 | * @return string |
||
2628 | */ |
||
2629 | public function SearchResultLink() |
||
2630 | { |
||
2631 | if ($this->HasSearchResults() && !$this->isSearchResults) { |
||
2632 | return $this->Link('searchresults'); |
||
2633 | } |
||
2634 | } |
||
2635 | |||
2636 | /**************************************************** |
||
2637 | * INTERNAL PROCESSING: PRODUCT LIST |
||
2638 | /****************************************************/ |
||
2639 | |||
2640 | /** |
||
2641 | * turns full list into paginated list. |
||
2642 | * |
||
2643 | * @param SS_List |
||
2644 | * |
||
2645 | * @return PaginatedList |
||
0 ignored issues
–
show
|
|||
2646 | */ |
||
2647 | protected function paginateList(SS_List $list) |
||
2648 | { |
||
2649 | if ($list && $list->count()) { |
||
2650 | if ($this->IsShowFullList()) { |
||
2651 | $obj = PaginatedList::create($list, $this->request); |
||
2652 | $obj->setPageLength(EcommerceConfig::get('ProductGroup', 'maximum_number_of_products_to_list') + 1); |
||
2653 | |||
2654 | return $obj; |
||
2655 | } else { |
||
2656 | $obj = PaginatedList::create($list, $this->request); |
||
2657 | $obj->setPageLength($this->MyNumberOfProductsPerPage()); |
||
2658 | |||
2659 | return $obj; |
||
2660 | } |
||
2661 | } |
||
2662 | } |
||
2663 | |||
2664 | /**************************************************** |
||
2665 | * INTERNAL PROCESSING: USER PREFERENCES |
||
2666 | /****************************************************/ |
||
2667 | |||
2668 | /** |
||
2669 | * Checks out a bunch of $_GET variables |
||
2670 | * that are used to work out user preferences |
||
2671 | * Some of these are saved to session. |
||
2672 | * |
||
2673 | * @param array $overrideArray - override $_GET variable settings |
||
2674 | */ |
||
2675 | protected function saveUserPreferences($overrideArray = array()) |
||
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a
Loading history...
|
|||
2676 | { |
||
2677 | |||
2678 | //save sort - filter - display |
||
2679 | $sortFilterDisplayNames = $this->getSortFilterDisplayNames(); |
||
2680 | foreach ($sortFilterDisplayNames as $type => $oneTypeArray) { |
||
2681 | $getVariableName = $oneTypeArray['getVariable']; |
||
2682 | $sessionName = $oneTypeArray['sessionName']; |
||
2683 | if (isset($overrideArray[$getVariableName])) { |
||
2684 | $newPreference = $overrideArray[$getVariableName]; |
||
2685 | } else { |
||
2686 | $newPreference = $this->request->getVar($getVariableName); |
||
2687 | } |
||
2688 | if ($newPreference) { |
||
2689 | $optionsVariableName = $oneTypeArray['configName']; |
||
2690 | $options = EcommerceConfig::get($this->ClassName, $optionsVariableName); |
||
2691 | if (isset($options[$newPreference])) { |
||
2692 | Session::set('ProductGroup_'.$sessionName, $newPreference); |
||
2693 | //save in model as well... |
||
2694 | } |
||
2695 | } else { |
||
2696 | $newPreference = Session::get('ProductGroup_'.$sessionName); |
||
2697 | } |
||
2698 | //save data in model... |
||
2699 | $this->setCurrentUserPreference($type, $newPreference); |
||
2700 | } |
||
2701 | /* save URLSegments in model |
||
2702 | $this->setCurrentUserPreference( |
||
2703 | "URLSegments", |
||
2704 | array( |
||
2705 | "Action" => $this->request->param("Action"), |
||
2706 | "ID" => $this->request->param("ID") |
||
2707 | ) |
||
2708 | ); |
||
2709 | */ |
||
2710 | |||
2711 | //clearing data.. |
||
2712 | if ($this->request->getVar('reload')) { |
||
2713 | //reset other session variables... |
||
2714 | Session::set($this->SearchResultsSessionVariable(false), ''); |
||
2715 | Session::set($this->SearchResultsSessionVariable(true), ''); |
||
2716 | |||
2717 | return $this->redirect($this->Link()); |
||
2718 | } |
||
2719 | |||
2720 | //full list .... |
||
2721 | if ($this->request->getVar('showfulllist')) { |
||
2722 | $this->showFullList = true; |
||
2723 | } |
||
2724 | } |
||
2725 | |||
2726 | /** |
||
2727 | * Checks for the most applicable user preferences for this user: |
||
2728 | * 1. session value |
||
2729 | * 2. getMyUserPreferencesDefault. |
||
2730 | * |
||
2731 | * @param string $type - FILTER | SORT | DISPLAY |
||
2732 | * |
||
2733 | * @return string |
||
2734 | * |
||
2735 | * @todo: move to controller? |
||
2736 | */ |
||
2737 | protected function getCurrentUserPreferences($type) |
||
2738 | { |
||
2739 | $sessionName = $this->getSortFilterDisplayNames($type, 'sessionName'); |
||
2740 | if ($sessionValue = Session::get('ProductGroup_'.$sessionName)) { |
||
2741 | $key = Convert::raw2sql($sessionValue); |
||
2742 | } else { |
||
2743 | $key = $this->getMyUserPreferencesDefault($type); |
||
2744 | } |
||
2745 | |||
2746 | return $key; |
||
2747 | } |
||
2748 | |||
2749 | /** |
||
2750 | * Provides a dataset of links for a particular user preference. |
||
2751 | * |
||
2752 | * @param string $type SORT | FILTER | DISPLAY - e.g. sort_options |
||
2753 | * |
||
2754 | * @return ArrayList( ArrayData(Name, Link, SelectKey, Current (boolean), LinkingMode)) |
||
0 ignored issues
–
show
The doc-type
ArrayList( could not be parsed: Expected "|" or "end of type", but got "(" at position 9. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.
Loading history...
|
|||
2755 | */ |
||
2756 | protected function userPreferencesLinks($type) |
||
2757 | { |
||
2758 | //get basics |
||
2759 | $sortFilterDisplayNames = $this->getSortFilterDisplayNames(); |
||
2760 | $options = $this->getConfigOptions($type); |
||
2761 | |||
2762 | //if there is only one option then do not bother |
||
2763 | if (count($options) < 2) { |
||
2764 | return; |
||
2765 | } |
||
2766 | |||
2767 | //get more config names |
||
2768 | $translationCode = $sortFilterDisplayNames[$type]['translationCode']; |
||
2769 | $getVariableName = $sortFilterDisplayNames[$type]['getVariable']; |
||
2770 | $arrayList = ArrayList::create(); |
||
2771 | if (count($options)) { |
||
2772 | foreach ($options as $key => $array) { |
||
2773 | //$isCurrent = ($key == $selectedItem) ? true : false; |
||
2774 | |||
2775 | $link = '?'.$getVariableName."=$key"; |
||
2776 | if ($type == 'FILTER') { |
||
2777 | $link = $this->Link().$link; |
||
2778 | } else { |
||
2779 | $link = $this->request->getVar('url').$link; |
||
2780 | } |
||
2781 | $arrayList->push(ArrayData::create(array( |
||
2782 | 'Name' => _t('ProductGroup.'.$translationCode.strtoupper(str_replace(' ', '', $array['Title'])), $array['Title']), |
||
2783 | 'Link' => $link, |
||
2784 | 'SelectKey' => $key, |
||
2785 | //we add current at runtime, so we can store the object without current set... |
||
2786 | //'Current' => $isCurrent, |
||
2787 | //'LinkingMode' => $isCurrent ? "current" : "link" |
||
2788 | ))); |
||
2789 | } |
||
2790 | } |
||
2791 | |||
2792 | return $arrayList; |
||
2793 | } |
||
2794 | |||
2795 | /**************************************************** |
||
2796 | * INTERNAL PROCESSING: TITLES |
||
2797 | /****************************************************/ |
||
2798 | |||
2799 | /** |
||
2800 | * variable to make sure secondary title only gets |
||
2801 | * added once. |
||
2802 | * |
||
2803 | * @var bool |
||
2804 | */ |
||
2805 | protected $secondaryTitleHasBeenAdded = false; |
||
2806 | |||
2807 | /** |
||
2808 | * add a secondary title to the main title |
||
2809 | * in case there is, for example, a filter applied |
||
2810 | * e.g. Socks | MyBrand. |
||
2811 | * |
||
2812 | * @param string |
||
2813 | */ |
||
2814 | protected function addSecondaryTitle($secondaryTitle = '') |
||
2815 | { |
||
2816 | $pipe = _t('ProductGroup.TITLE_SEPARATOR', ' | '); |
||
2817 | if (! $this->secondaryTitleHasBeenAdded) { |
||
2818 | if (trim($secondaryTitle)) { |
||
2819 | $secondaryTitle = $pipe.$secondaryTitle; |
||
2820 | } |
||
2821 | if ($this->IsSearchResults()) { |
||
2822 | if ($array = $this->searchResultsArrayFromSession()) { |
||
2823 | //we remove 1 item here, because the array starts with 0 => 0 |
||
2824 | $count = count($array) - 1; |
||
2825 | if ($count > 3) { |
||
2826 | $toAdd = $count. ' '._t('ProductGroup.PRODUCTS_FOUND', 'Products Found'); |
||
2827 | $secondaryTitle .= $this->cleanSecondaryTitleForAddition($pipe, $toAdd); |
||
2828 | } |
||
2829 | } else { |
||
2830 | $toAdd = _t('ProductGroup.SEARCH_RESULTS', 'Search Results'); |
||
2831 | $secondaryTitle .= $this->cleanSecondaryTitleForAddition($pipe, $toAdd); |
||
2832 | } |
||
2833 | } |
||
2834 | if (is_object($this->filterForGroupObject)) { |
||
2835 | $toAdd = $this->filterForGroupObject->Title; |
||
2836 | $secondaryTitle .= $this->cleanSecondaryTitleForAddition($pipe, $toAdd); |
||
2837 | } |
||
2838 | if ($this->IsShowFullList()) { |
||
2839 | $toAdd = _t('ProductGroup.LIST_VIEW', 'List View'); |
||
2840 | $secondaryTitle .= $this->cleanSecondaryTitleForAddition($pipe, $toAdd); |
||
2841 | } |
||
2842 | $filter = $this->getCurrentUserPreferences('FILTER'); |
||
2843 | if ($filter != $this->getMyUserPreferencesDefault('FILTER')) { |
||
2844 | $toAdd = $this->getUserPreferencesTitle('FILTER', $this->getCurrentUserPreferences('FILTER')); |
||
2845 | $secondaryTitle .= $this->cleanSecondaryTitleForAddition($pipe, $toAdd); |
||
2846 | } |
||
2847 | if ($this->HasSort()) { |
||
2848 | $toAdd = $this->getUserPreferencesTitle('SORT', $this->getCurrentUserPreferences('SORT')); |
||
2849 | $secondaryTitle .= $this->cleanSecondaryTitleForAddition($pipe, $toAdd); |
||
2850 | } |
||
2851 | if ($secondaryTitle) { |
||
2852 | $this->Title .= $secondaryTitle; |
||
2853 | if (isset($this->MetaTitle)) { |
||
2854 | $this->MetaTitle .= $secondaryTitle; |
||
2855 | } |
||
2856 | } |
||
2857 | //dont update menu title, because the entry in the menu |
||
2858 | //should stay the same as it links back to the unfiltered |
||
2859 | //page (in some cases). |
||
2860 | $this->secondaryTitleHasBeenAdded = true; |
||
2861 | } |
||
2862 | } |
||
2863 | |||
2864 | /** |
||
2865 | * removes any spaces from the 'toAdd' bit and adds the pipe if there is |
||
2866 | * anything to add at all. Through the lang files, you can change the pipe |
||
2867 | * symbol to anything you like. |
||
2868 | * |
||
2869 | * @param string $pipe |
||
2870 | * @param string $toAdd |
||
2871 | * @return string |
||
2872 | */ |
||
2873 | protected function cleanSecondaryTitleForAddition($pipe, $toAdd) |
||
2874 | { |
||
2875 | $toAdd = trim($toAdd); |
||
2876 | $length = strlen($toAdd); |
||
2877 | if ($length > 0) { |
||
2878 | $toAdd = $pipe.$toAdd; |
||
2879 | } |
||
2880 | return $toAdd; |
||
2881 | } |
||
2882 | |||
2883 | /**************************************************** |
||
2884 | * DEBUG |
||
2885 | /****************************************************/ |
||
2886 | |||
2887 | public function debug() |
||
2888 | { |
||
2889 | $member = Member::currentUser(); |
||
2890 | if (!$member || !$member->IsShopAdmin()) { |
||
2891 | $messages = array( |
||
2892 | 'default' => 'You must login as an admin to use debug functions.', |
||
2893 | ); |
||
2894 | Security::permissionFailure($this, $messages); |
||
2895 | } |
||
2896 | $this->ProductsShowable(); |
||
2897 | $html = EcommerceTaskDebugCart::debug_object($this->dataRecord); |
||
2898 | $html .= '<ul>'; |
||
2899 | |||
2900 | $html .= '<li><hr /><h3>Available options</h3><hr /></li>'; |
||
2901 | $html .= '<li><b>Sort Options for Dropdown:</b><pre> '.print_r($this->getUserPreferencesOptionsForDropdown('SORT'), 1).'</pre> </li>'; |
||
2902 | $html .= '<li><b>Filter Options for Dropdown:</b><pre> '.print_r($this->getUserPreferencesOptionsForDropdown('FILTER'), 1).'</pre></li>'; |
||
2903 | $html .= '<li><b>Display Styles for Dropdown:</b><pre> '.print_r($this->getUserPreferencesOptionsForDropdown('DISPLAY'), 1).'</pre> </li>'; |
||
2904 | |||
2905 | $html .= '<li><hr /><h3>Selection Setting (what is set as default for this page)</h3><hr /></li>'; |
||
2906 | $html .= '<li><b>MyDefaultFilter:</b> '.$this->getMyUserPreferencesDefault('FILTER').' </li>'; |
||
2907 | $html .= '<li><b>MyDefaultSortOrder:</b> '.$this->getMyUserPreferencesDefault('SORT').' </li>'; |
||
2908 | $html .= '<li><b>MyDefaultDisplayStyle:</b> '.$this->getMyUserPreferencesDefault('DISPLAY').' </li>'; |
||
2909 | $html .= '<li><b>MyNumberOfProductsPerPage:</b> '.$this->MyNumberOfProductsPerPage().' </li>'; |
||
2910 | $html .= '<li><b>MyLevelOfProductsToshow:</b> '.$this->MyLevelOfProductsToShow().' = '.(isset($this->showProductLevels[$this->MyLevelOfProductsToShow()]) ? $this->showProductLevels[$this->MyLevelOfProductsToShow()] : 'ERROR!!!! $this->showProductLevels not set for '.$this->MyLevelOfProductsToShow()).' </li>'; |
||
2911 | |||
2912 | $html .= '<li><hr /><h3>Current Settings</h3><hr /></li>'; |
||
2913 | $html .= '<li><b>Current Sort Order:</b> '.$this->getCurrentUserPreferences('SORT').' </li>'; |
||
2914 | $html .= '<li><b>Current Filter:</b> '.$this->getCurrentUserPreferences('FILTER').' </li>'; |
||
2915 | $html .= '<li><b>Current display style:</b> '.$this->getCurrentUserPreferences('DISPLAY').' </li>'; |
||
2916 | |||
2917 | $html .= '<li><hr /><h3>DATALIST: totals, numbers per page etc</h3><hr /></li>'; |
||
2918 | $html .= '<li><b>Total number of products:</b> '.$this->TotalCount().' </li>'; |
||
2919 | $html .= '<li><b>Is there more than one product:</b> '.($this->TotalCountGreaterThanOne() ? 'YES' : 'NO').' </li>'; |
||
2920 | $html .= '<li><b>Number of products per page:</b> '.$this->MyNumberOfProductsPerPage().' </li>'; |
||
2921 | |||
2922 | $html .= '<li><hr /><h3>SQL Factors</h3><hr /></li>'; |
||
2923 | $html .= '<li><b>Default sort SQL:</b> '.print_r($this->getUserSettingsOptionSQL('SORT'), 1).' </li>'; |
||
2924 | $html .= '<li><b>User sort SQL:</b> '.print_r($this->getUserSettingsOptionSQL('SORT', $this->getCurrentUserPreferences('SORT')), 1).' </li>'; |
||
2925 | $html .= '<li><b>Default Filter SQL:</b> <pre>'.print_r($this->getUserSettingsOptionSQL('FILTER'), 1).'</pre> </li>'; |
||
2926 | $html .= '<li><b>User Filter SQL:</b> <pre>'.print_r($this->getUserSettingsOptionSQL('FILTER', $this->getCurrentUserPreferences('FILTER')), 1).'</pre> </li>'; |
||
2927 | $html .= '<li><b>Buyable Class name:</b> '.$this->getBuyableClassName().' </li>'; |
||
2928 | $html .= '<li><b>allProducts:</b> '.print_r(str_replace('"', '`', $this->allProducts->sql()), 1).' </li>'; |
||
2929 | |||
2930 | $html .= '<li><hr /><h3>Search</h3><hr /></li>'; |
||
2931 | $resultArray = $this->searchResultsArrayFromSession(); |
||
2932 | $productGroupArray = explode(',', Session::get($this->SearchResultsSessionVariable(true))); |
||
2933 | $html .= '<li><b>Is Search Results:</b> '.($this->IsSearchResults() ? 'YES' : 'NO').' </li>'; |
||
2934 | $html .= '<li><b>Products In Search (session variable : '.$this->SearchResultsSessionVariable(false).'):</b> '.print_r($resultArray, 1).' </li>'; |
||
2935 | $html .= '<li><b>Product Groups In Search (session variable : '.$this->SearchResultsSessionVariable(true).'):</b> '.print_r($productGroupArray, 1).' </li>'; |
||
2936 | |||
2937 | $html .= '<li><hr /><h3>Other</h3><hr /></li>'; |
||
2938 | if ($image = $this->BestAvailableImage()) { |
||
2939 | $html .= '<li><b>Best Available Image:</b> <img src="'.$image->Link.'" /> </li>'; |
||
2940 | } |
||
2941 | $html .= '<li><b>BestAvailableImage:</b> '.($this->BestAvailableImage() ? $this->BestAvailableImage()->Link : 'no image available').' </li>'; |
||
2942 | $html .= '<li><b>Is this an ecommerce page:</b> '.($this->IsEcommercePage() ? 'YES' : 'NO').' </li>'; |
||
2943 | $html .= '<li><hr /><h3>Related Groups</h3><hr /></li>'; |
||
2944 | $html .= '<li><b>Parent product group:</b> '.($this->ParentGroup() ? $this->ParentGroup()->Title : '[NO PARENT GROUP]').'</li>'; |
||
2945 | |||
2946 | $childGroups = $this->ChildGroups(99); |
||
2947 | if ($childGroups->count()) { |
||
2948 | $childGroups = $childGroups->map('ID', 'MenuTitle'); |
||
2949 | $html .= '<li><b>Child Groups (all):</b><pre> '.print_r($childGroups, 1).' </pre></li>'; |
||
2950 | } else { |
||
2951 | $html .= '<li><b>Child Groups (full tree): </b>NONE</li>'; |
||
2952 | } |
||
2953 | $html .= '<li><b>a list of Product Groups that have the products for the CURRENT product group listed as part of their AlsoShowProducts list:</b><pre>'.print_r($this->ProductGroupsFromAlsoShowProducts()->map('ID', 'Title')->toArray(), 1).' </pre></li>'; |
||
2954 | $html .= '<li><b>the inverse of ProductGroupsFromAlsoShowProducts:</b><pre> '.print_r($this->ProductGroupsFromAlsoShowProductsInverse()->map('ID', 'Title')->toArray(), 1).' </pre></li>'; |
||
2955 | $html .= '<li><b>all product parent groups:</b><pre> '.print_r($this->ProductGroupsParentGroups()->map('ID', 'Title')->toArray(), 1).' </pre></li>'; |
||
2956 | |||
2957 | $html .= '<li><hr /><h3>Product Example and Links</h3><hr /></li>'; |
||
2958 | $product = DataObject::get_one( |
||
2959 | 'Product', |
||
2960 | array('ParentID' => $this->ID) |
||
2961 | ); |
||
2962 | if ($product) { |
||
2963 | $html .= '<li><b>Product View:</b> <a href="'.$product->Link().'">'.$product->Title.'</a> </li>'; |
||
2964 | $html .= '<li><b>Product Debug:</b> <a href="'.$product->Link('debug').'">'.$product->Title.'</a> </li>'; |
||
2965 | $html .= '<li><b>Product Admin Page:</b> <a href="'.'/admin/pages/edit/show/'.$product->ID.'">'.$product->Title.'</a> </li>'; |
||
2966 | $html .= '<li><b>ProductGroup Admin Page:</b> <a href="'.'/admin/pages/edit/show/'.$this->ID.'">'.$this->Title.'</a> </li>'; |
||
2967 | } else { |
||
2968 | $html .= '<li>this page has no products of its own</li>'; |
||
2969 | } |
||
2970 | $html .= '</ul>'; |
||
2971 | |||
2972 | return $html; |
||
2973 | } |
||
2974 | } |
||
2975 |
Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a
@return
annotation as described here.