synonyms_commerce.module 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. /**
  3. * @file
  4. * Provides synonyms integration with Commerce.
  5. */
  6. /**
  7. * Implements hook_menu().
  8. */
  9. function synonyms_commerce_menu() {
  10. $items = array();
  11. $items['synonyms-commerce/autocomplete'] = array(
  12. 'title' => 'Synonyms-friendly product autocomplete widget',
  13. 'page callback' => 'synonyms_commerce_autocomplete',
  14. 'access callback' => TRUE,
  15. 'type' => MENU_CALLBACK,
  16. 'file' => 'synonyms_commerce.pages.inc',
  17. );
  18. return $items;
  19. }
  20. /**
  21. * Implements hook_field_widget_info().
  22. */
  23. function synonyms_commerce_field_widget_info() {
  24. return array(
  25. 'synonyms_commerce_autocomplete' => array(
  26. 'label' => t('Synonyms friendly autocomplete'),
  27. 'field types' => array('commerce_product_reference'),
  28. 'settings' => array(
  29. 'size' => 60,
  30. 'synonyms_autocomplete_path' => 'synonyms-commerce/autocomplete',
  31. 'suggestion_size' => 10,
  32. 'suggest_only_unique' => FALSE,
  33. ),
  34. 'behaviors' => array(
  35. 'multiple values' => FIELD_BEHAVIOR_CUSTOM,
  36. ),
  37. ),
  38. 'synonyms_commerce_select' => array(
  39. 'label' => t('Synonyms friendly select list'),
  40. 'field types' => array('commerce_product_reference'),
  41. 'settings' => array(),
  42. 'behaviors' => array(
  43. 'multiple values' => FIELD_BEHAVIOR_CUSTOM,
  44. ),
  45. ),
  46. );
  47. }
  48. /**
  49. * Implements hook_field_widget_settings_form().
  50. */
  51. function synonyms_commerce_field_widget_settings_form($field, $instance) {
  52. $widget = $instance['widget'];
  53. $settings = $widget['settings'] + field_info_widget_settings($widget['type']);
  54. $form = array();
  55. switch ($widget['type']) {
  56. case 'synonyms_commerce_autocomplete':
  57. $form['suggestion_size'] = array(
  58. '#type' => 'textfield',
  59. '#title' => t('Suggestions Size'),
  60. '#description' => t('Please, enter how many suggested entities to show in the autocomplete textfield.'),
  61. '#required' => TRUE,
  62. '#element_validate' => array('element_validate_integer_positive'),
  63. '#default_value' => $settings['suggestion_size'],
  64. );
  65. $form['suggest_only_unique'] = array(
  66. '#type' => 'checkbox',
  67. '#title' => t('Suggest only one entry per product'),
  68. '#description' => t('If you want to include only product name or a single synonym, suggesting a particular product, while disregarding all ongoing ones, please, tick this checkbox on.'),
  69. '#default_value' => $settings['suggest_only_unique'],
  70. );
  71. break;
  72. }
  73. return $form;
  74. }
  75. /**
  76. * Implements hook_field_widget_form().
  77. */
  78. function synonyms_commerce_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  79. $default_value = synonyms_select_default_value($field, $instance, $items);
  80. switch ($instance['widget']['type']) {
  81. case 'synonyms_commerce_autocomplete':
  82. $default_value_string = array();
  83. foreach (commerce_product_load_multiple($default_value) as $product) {
  84. $default_value_string[] = entity_label('commerce_product', $product);
  85. }
  86. $default_value_string = drupal_implode_tags($default_value_string);
  87. $element += array(
  88. '#type' => 'textfield',
  89. '#default_value' => $default_value_string,
  90. '#autocomplete_path' => $instance['widget']['settings']['synonyms_autocomplete_path'] . '/' . $field['field_name'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'],
  91. '#size' => $instance['widget']['settings']['size'],
  92. '#maxlength' => 1024,
  93. '#element_validate' => array('synonyms_commerce_autocomplete_validate'),
  94. '#attached' => array(
  95. 'js' => array(
  96. drupal_get_path('module', 'synonyms') . '/js/synonyms-autocomplete.js' => array(),
  97. ),
  98. ),
  99. '#attributes' => array(
  100. 'class' => array('synonyms-autocomplete'),
  101. ),
  102. );
  103. if (isset($instance['widget']['settings']['auto_creation'])) {
  104. $element['#auto_creation'] = $instance['widget']['settings']['auto_creation'];
  105. }
  106. break;
  107. case 'synonyms_commerce_select':
  108. $multiple = $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED;
  109. $options = module_invoke('commerce_product_reference', 'options_list', $field, $instance);
  110. $tmp = reset($options);
  111. if (is_array($tmp)) {
  112. // These options have optgroups.
  113. foreach ($options as $k => $v) {
  114. $options[$k] = synonyms_commerce_product_options_expand($v);
  115. }
  116. }
  117. else {
  118. $options = synonyms_commerce_product_options_expand($options);
  119. }
  120. $element += array(
  121. '#type' => 'select',
  122. '#empty_option' => t('- None -'),
  123. '#options' => $options,
  124. '#multiple' => $multiple,
  125. '#element_validate' => array('synonyms_select_validate', 'synonyms_select_form_to_storage'),
  126. '#default_value' => $default_value,
  127. );
  128. break;
  129. }
  130. return $element;
  131. }
  132. /**
  133. * Implements hook_synonyms_provider_field_behavior_implementation_info().
  134. */
  135. function synonyms_commerce_synonyms_provider_field_behavior_implementation_info($behavior) {
  136. switch ($behavior) {
  137. case 'select':
  138. case 'autocomplete':
  139. return array(
  140. 'commerce_product_reference' => 'CommerceProductReferenceSynonymsBehavior',
  141. );
  142. break;
  143. }
  144. return array();
  145. }
  146. /**
  147. * Expand the options for commerce product select widget with synonyms.
  148. *
  149. * @param array $options
  150. * Array of commerce product reference widget options that should be expanded
  151. * with synonyms
  152. *
  153. * @return array
  154. * Expanded with synonyms version of the provided $options
  155. */
  156. function synonyms_commerce_product_options_expand($options) {
  157. $synonyms_options = array();
  158. $behavior_implementations = array();
  159. foreach (commerce_product_load_multiple(array_keys($options)) as $product) {
  160. if (!isset($behavior_implementations[$product->type])) {
  161. $behavior_implementations[$product->type] = synonyms_behavior_get('select', 'commerce_product', $product->type, TRUE);
  162. }
  163. $synonyms_options[] = synonyms_select_option_entity($product, 'commerce_product');
  164. foreach ($behavior_implementations[$product->type] as $behavior_implementation) {
  165. foreach ($behavior_implementation['object']->extractSynonyms($product) as $synonym) {
  166. $synonyms_options[] = synonyms_select_option_entity($product, $behavior_implementation['entity_type'], $synonym, $behavior_implementation);
  167. }
  168. }
  169. }
  170. usort($synonyms_options , 'synonyms_select_sort_name');
  171. return $synonyms_options;
  172. }
  173. /**
  174. * Element validate for commerce product synonyms friendly autocomplete widget.
  175. */
  176. function synonyms_commerce_autocomplete_validate($element, &$form_state) {
  177. $input = drupal_map_assoc(drupal_explode_tags(drupal_strtolower($element['#value'])));
  178. $value = array();
  179. $field = field_info_field($element['#field_name']);
  180. $instance = field_info_instance($element['#entity_type'], $field['field_name'], $element['#bundle']);
  181. if (!empty($input)) {
  182. $target_bundles = synonyms_bundle_normalize('commerce_product', array_filter($instance['settings']['referenceable_types']));
  183. $efq = new EntityFieldQuery();
  184. $efq->entityCondition('entity_type', 'commerce_product');
  185. $efq->entityCondition('bundle', $target_bundles);
  186. $efq->propertyCondition('title', $input, 'IN');
  187. $result = $efq->execute();
  188. if (isset($result['commerce_product'])) {
  189. foreach (commerce_product_load_multiple(array_keys($result['commerce_product'])) as $product) {
  190. $label = drupal_strtolower(entity_label('commerce_product', $product));
  191. unset($input[$label]);
  192. $entity_id = entity_extract_ids('commerce_product', $product);
  193. $value[] = $entity_id[0];
  194. }
  195. }
  196. if (!empty($input)) {
  197. $behavior_implementations = synonyms_behavior_get('autocomplete', 'commerce_product', $target_bundles, TRUE);
  198. foreach ($behavior_implementations as $implementation) {
  199. $condition = db_and();
  200. $condition->condition(AbstractSynonymsBehavior::COLUMN_SYNONYM_PLACEHOLDER, $input, 'IN');
  201. foreach ($implementation['object']->synonymsFind($condition) as $synonym) {
  202. $value[] = $synonym->entity_id;
  203. unset($input[drupal_strtolower($synonym->synonym)]);
  204. if (empty($input)) {
  205. break(2);
  206. }
  207. }
  208. }
  209. }
  210. }
  211. $tmp = array_unique($value);
  212. $value = array();
  213. $column = array_keys($field['columns']);
  214. $column = reset($column);
  215. foreach ($tmp as $target_id) {
  216. $value[] = array($column => $target_id);
  217. }
  218. form_set_value($element, $value, $form_state);
  219. }