Project

General

Profile

Paste
Download (6.99 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / flag / includes / views / flag_plugin_argument_validate_flaggability.inc @ 4cfd8be6

1
<?php
2

    
3
/**
4
 * @file
5
 * Contains the flaggability validator handler.
6
 */
7

    
8
/**
9
 * Validates whether an argument is a flaggable/flagged object.
10
 *
11
 * @ingroup views
12
 */
13
class flag_plugin_argument_validate_flaggability extends views_plugin_argument_validate {
14

    
15
  function construct() {
16
    parent::construct();
17
    $this->flag_type = $this->definition['flag type'];
18
  }
19

    
20
  function option_definition() {
21
    $options = parent::option_definition();
22
    $options['flag_name'] = array('default' => '*relationship*');
23
    $options['flag_test'] = array('default' => 'flaggable');
24
    $options['flag_id_type'] = array('default' => 'id');
25
    return $options;
26
  }
27

    
28
  function options_form(&$form, &$form_state) {
29
    // If there are no flag relationships set, skip this form of validation.
30
    $flags = flag_get_flags($this->flag_type);
31
    if (!$flags) {
32
      return array();
33
    }
34
    $options = $this->flags_options();
35

    
36
    $form['flag_name'] = array(
37
      '#type' => 'radios',
38
      '#title' => t('Flag'),
39
      '#options' => $options,
40
      '#default_value' => $this->options['flag_name'],
41
      '#description' => t('Select the flag to validate against.'),
42
    );
43
    if (!$options) {
44
      $form['flag_name']['#description'] = '<p class="warning">' . t('No %type flags exist. You must first <a href="@create-url">create a %type flag</a> before being able to use one.', array('%type' => $this->flag_type, '@create-url' => FLAG_ADMIN_PATH)) . '</p>';
45
    }
46

    
47
    $form['flag_test'] = array(
48
      '#type' => 'select',
49
      '#title' => t('Validate the @type only if', array('@type' => $this->flag_type)),
50
      '#options' => $this->tests_options(),
51
      '#default_value' => $this->options['flag_test'],
52
    );
53

    
54
    // This validator supports the "multiple IDs" syntax. It may not be
55
    // extremely useful, but similar validators do support this and it's a good
56
    // thing to be compatible.
57
    $form['flag_id_type'] = array(
58
      '#type' => 'select',
59
      '#title' => t('Argument type'),
60
      '#options' => array(
61
        'id' => t('ID'),
62
        'ids' => t('IDs separated by , or +'),
63
      ),
64
      '#default_value' => $this->options['flag_id_type'],
65
    );
66
  }
67

    
68
  /**
69
   * Returns form #options for the flags.
70
   *
71
   * Returns empty array if no flags were found.
72
   */
73
  function flags_options() {
74
    $flags = flag_get_flags($this->flag_type);
75
    if (!$flags) {
76
      return array();
77
    }
78
    else {
79
      foreach ($flags as $flag) {
80
        $options[$flag->name] = $flag->get_title();
81
      }
82
      $options['*relationship*'] = t('<em>Pick the first flag mentioned in the relationships.</em>');
83
      return $options;
84
    }
85
  }
86

    
87
  /**
88
   * Migrate existing Views 2 options to Views 3.
89
   */
90
  function convert_options(&$options) {
91
    $prefix = 'validate_argument_' . $this->flag_type . '_';
92
    if (!isset($options['flag_name']) && !empty($this->argument->options[$prefix . 'flag_name'])) {
93
      $options['flag_name'] = $this->argument->options[$prefix . 'flag_name'];
94
      $options['flag_test'] = $this->argument->options[$prefix . 'flag_test'];
95
      $options['flag_id_type'] = $this->argument->options[$prefix . 'flag_id_type'];
96
    }
97
  }
98

    
99
  /**
100
   * Declares all tests.
101
   *
102
   * This scheme makes it easy for derived classes to add and remove tests.
103
   */
104
  function tests_info($which = NULL) {
105
    return array(
106
      'flaggable' => array(
107
        'title' => t('It is flaggable'),
108
        'callback' => 'test_flaggable',
109
      ),
110
      'flagged' => array(
111
        'title' => t('It is flagged at least once'),
112
        'callback' => 'test_flagged',
113
      ),
114
      'flagged_by_current_user' => array(
115
        'title' => t('It is flagged by the current user'),
116
        'callback' => 'test_flagged_by_current_user',
117
      ),
118
    );
119
  }
120

    
121
  function tests_options() {
122
    $options = array();
123
    foreach ($this->tests_info() as $id => $info) {
124
      $options[$id] = $info['title'];
125
    }
126
    return $options;
127
  }
128

    
129
  function get_flag() {
130
    $flag_name = $this->options['flag_name'];
131

    
132
    if ($flag_name == '*relationship*') {
133
      // Pick the first flag mentioned in the relationships.
134
      foreach ($this->view->relationship as $id => $handler) {
135
        // Note: we can't do $handler->field, because the relationship handler's
136
        // init() may overwrite it.
137
        if (strpos($handler->options['field'], 'flag') !== FALSE && !empty($handler->options['flag'])) {
138
          $flag = flag_get_flag($handler->options['flag']);
139
          if ($flag && $flag->entity_type == $this->flag_type) {
140
            return $flag;
141
          }
142
        }
143
      }
144
    }
145

    
146
    return flag_get_flag($flag_name);
147
  }
148

    
149
  /**
150
   * Tests whether the argument is flaggable, or flagged, or flagged by current
151
   * user. These are three possible tests, and which of the three to actually
152
   * carry out is determined by 'flag_test'.
153
   */
154
  function validate_argument($argument) {
155
    $flag_test = $this->options['flag_test'];
156
    $id_type   = $this->options['flag_id_type'];
157

    
158
    $flag = $this->get_flag();
159
    if (!$flag) {
160
      // Validator is misconfigured somehow.
161
      return TRUE;
162
    }
163

    
164
    if ($id_type == 'id') {
165
      if (!is_numeric($argument)) {
166
        // If a user is being smart and types several IDs where only one is
167
        // expected, we invalidate this.
168
        return FALSE;
169
      }
170
    }
171

    
172
    $ids = views_break_phrase($argument, $this);
173
    if ($ids->value == array(-1)) {
174
      // Malformed argument syntax. Invalidate.
175
      return FALSE;
176
    }
177
    $ids = $ids->value;
178

    
179
    // Delegate the testing to the particual test method. $passed then
180
    // holds the IDs that passed the test.
181
    $tests_info = $this->tests_info();
182
    $method = $tests_info[$flag_test]['callback'];
183
    if (method_exists($this, $method)) {
184
      $passed = $this->$method($ids, $flag);
185
    }
186
    else {
187
      $passed = array();
188
    }
189

    
190
    // If some IDs exist that haven't $passed our test then validation fails.
191
    $failed = array_diff($ids, $passed);
192
    return empty($failed);
193
  }
194

    
195
  //
196
  // The actual tests. They return the IDs that passed.
197
  //
198

    
199
  function test_flaggable($ids, $flag) {
200
    return array_filter($ids, array($flag, 'applies_to_entity_id'));
201
  }
202

    
203
  function test_flagged($ids, $flag) {
204
    // view_break_phrase() is guaranteed to return only integers, so this is SQL
205
    // safe.
206
    $flattened_ids = implode(',', $ids);
207
    return $this->_test_by_sql("SELECT entity_id FROM {flag_counts} WHERE fid = :fid AND entity_id IN ($flattened_ids) AND count > 0", array(':fid' => $flag->fid));
208
  }
209

    
210
  function test_flagged_by_current_user($ids, $flag) {
211
    global $user;
212
    if (!$user->uid) {
213
      // Anonymous user.
214
      return array();
215
    }
216
    $flattened_ids = implode(',', $ids);
217
    return $this->_test_by_sql("SELECT entity_id FROM {flagging} WHERE fid = :fid AND entity_id IN ($flattened_ids) AND uid = :uid", array(':fid' => $flag->fid, ':uid' => $user->uid));
218
  }
219

    
220
  // Helper: executes an SQL query and returns all the entity_id's.
221
  function _test_by_sql($sql, $args) {
222
    $passed = array();
223
    $result = db_query($sql, $args);
224
    foreach ($result as $row) {
225
      $passed[] = $row->entity_id;
226
    }
227
    return $passed;
228
  }
229
}