flag_handler_field_ops.inc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. <?php
  2. /**
  3. * @file
  4. * Contains the flag Ops field handler.
  5. */
  6. /**
  7. * Views field handler for the Flag operations links (flag/unflag).
  8. *
  9. * @ingroup views
  10. */
  11. class flag_handler_field_ops extends views_handler_field {
  12. /**
  13. * Returns the flag object associated with our field.
  14. *
  15. * A field is in some relationship. This function reaches out for this
  16. * relationship and reads its 'flag' option, which holds the flag name.
  17. */
  18. function get_flag() {
  19. // When editing a view it's possible to delete the relationship (either by
  20. // error or to later recreate it), so we have to guard against a missing
  21. // one.
  22. if (isset($this->view->relationship[$this->options['relationship']])) {
  23. return $this->view->relationship[$this->options['relationship']]->get_flag();
  24. }
  25. }
  26. /**
  27. * Return the the relationship we're linked to. That is, the alias for its
  28. * table (which is suitbale for use with the various methods of the 'query'
  29. * object).
  30. */
  31. function get_parent_relationship() {
  32. $parent = $this->view->relationship[$this->options['relationship']]->options['relationship'];
  33. if (!$parent || $parent == 'none') {
  34. // Base query table.
  35. return NULL;
  36. }
  37. else {
  38. return $this->view->relationship[$parent]->alias;
  39. }
  40. }
  41. function option_definition() {
  42. $options = parent::option_definition();
  43. $options['link_type'] = array('default' => '');
  44. return $options;
  45. }
  46. function options_form(&$form, &$form_state) {
  47. parent::options_form($form, $form_state);
  48. $form['link_type'] = array(
  49. '#type' => 'radios',
  50. '#title' => t('Link type'),
  51. '#options' => array('' => t('Use flag link settings')) + _flag_link_type_options(),
  52. '#default_value' => $this->options['link_type'],
  53. );
  54. }
  55. /**
  56. * Override base ::query(). The purpose here is to make it possible for the
  57. * render() method to know two things: what's the content ID, and whether
  58. * it's flagged.
  59. */
  60. function query() {
  61. if (!($flag = $this->get_flag())) {
  62. // Error message is printed in render().
  63. return;
  64. }
  65. $info = $flag->get_views_info();
  66. $parent = $this->get_parent_relationship();
  67. // Find out if the content is flagged. We can't just peek at some field in
  68. // our loaded table because it doesn't always reflect the user browsing the
  69. // page. So we explicitly add the flagging table to find this out.
  70. // If the relationship is created with 'Current User' checked, we probably
  71. // already have the appropriate join. We just need the appropriate table
  72. // alias for that join. We look in the relationship settings to see if
  73. // user_scope is set to 'current' to determine this.
  74. $relationship = $this->view->relationship[$this->options['relationship']];
  75. if (isset($relationship->options['user_scope']) && $relationship->options['user_scope'] == 'current') {
  76. $table_alias = $relationship->alias;
  77. }
  78. // Otherwise, let's set up the alias, keeping it unique for this flag in
  79. // case there are multiple flag relationships in a single view.
  80. else {
  81. $table_alias = 'flagging_current_user_' . $flag->fid;
  82. }
  83. // Now that we have the table alias, let's see if it's already been joined
  84. // to. If it hasn't, we'll set up a join.
  85. if (!isset($this->query->table_queue[$table_alias])) {
  86. $join = new views_join();
  87. $join->construct('flagging', $info['views table'], $info['join field'], 'entity_id');
  88. $join->extra[] = array(
  89. 'field' => 'fid',
  90. 'value' => $flag->fid,
  91. 'numeric' => TRUE,
  92. );
  93. if (!$flag->global) {
  94. $join->extra[] = array(
  95. 'field' => 'uid',
  96. 'value' => '***CURRENT_USER***',
  97. 'numeric' => TRUE,
  98. );
  99. $join->extra[] = array(
  100. 'field' => 'sid',
  101. 'value' => '***FLAG_CURRENT_USER_SID***',
  102. 'numeric' => TRUE,
  103. );
  104. }
  105. $table_alias = $this->query->add_table($table_alias, $parent, $join);
  106. }
  107. $this->aliases['is_flagged'] = $this->query->add_field($table_alias, 'entity_id');
  108. // Next, find out the content ID. We can't add_field() on this table
  109. // (flagging), because its entity_id may be NULL (in case no user has
  110. // flagged this content, and it's a LEFT JOIN). So we reach to the parent
  111. // relationship and add_field() *its* content ID column.
  112. $left_table = $this->view->relationship[$this->options['relationship']]->table_alias;
  113. $this->aliases['entity_id'] = $this->query->add_field($left_table, $info['join field']);
  114. }
  115. /**
  116. * Find out if the flag applies to each item seen on the page. It's done in a
  117. * separate DB query to to avoid complexity and to make 'many to one' tests
  118. * (e.g. checking user roles) possible without causing duplicate rows.
  119. */
  120. function pre_render(&$values) {
  121. if (!($flag = $this->get_flag())) {
  122. // Error message is printed in render().
  123. return;
  124. }
  125. $ids = array();
  126. foreach ($values as $row) {
  127. $entity_id = $row->{$this->aliases['entity_id']};
  128. $is_flagged = $row->{$this->aliases['is_flagged']};
  129. if (isset($entity_id)) {
  130. $ids[$entity_id] = $is_flagged ? 'unflag' : 'flag';
  131. }
  132. }
  133. $this->flag_applies = $ids ? $flag->access_multiple($ids) : array();
  134. }
  135. function render($values) {
  136. if (!($flag = $this->get_flag())) {
  137. // get_flag() itself will print a more detailed message.
  138. return t('Missing flag');
  139. }
  140. $entity_id = $values->{$this->aliases['entity_id']};
  141. $is_flagged = $values->{$this->aliases['is_flagged']};
  142. if (empty($this->flag_applies[$entity_id])) {
  143. // Flag does not apply to this content.
  144. return;
  145. }
  146. if (!empty($this->options['link_type'])) {
  147. $flag->link_type = $this->options['link_type'];
  148. }
  149. return $flag->theme($is_flagged ? 'unflag' : 'flag', $entity_id);
  150. }
  151. }