root/drupal-6/sites/all/modules/flag/includes/flag_plugin_argument_validate_flaggability.inc @ 867

Revision 867, 7.7 KB (checked in by frans, 6 months ago)

update: flag to 6.x-2.x-dev version

Line 
1<?php
2// $Id: flag_plugin_argument_validate_flaggability.inc,v 1.1.2.3.2.1 2009/09/14 11:46:40 quicksketch Exp $
3
4/**
5 * @file
6 * Contains the flaggability validator handler.
7 */
8
9/**
10 * Validates whether an argument is a flaggable/flagged object.
11 *
12 * @ingroup views
13 */
14class flag_plugin_argument_validate_flaggability extends views_plugin_argument_validate {
15
16  function construct() {
17    parent::construct();
18    $this->flag_type = $this->definition['flag type'];
19  }
20
21  function validate_form(&$form, &$form_state) {
22    $options = $this->flags_options();
23
24    $form[$this->_option_name('flag_name')] = array(
25      '#type' => 'radios',
26       // Add an ID to the surrounding div because radios don't get IDs
27       // as a whole group. This is needed for #dependency.
28      '#prefix' => '<div><div id="edit-options-' . views_css_safe($this->_option_name('flag_name')) . '">',
29      '#suffix' => '</div></div>',
30      '#title' => t('Flag'),
31      '#options' => $options,
32      '#default_value' => $this->_get_option('flag_name', '*relationship*'),
33      '#description' => t('Select the flag to validate against.'),
34      '#process' => array('expand_radios', 'views_process_dependency'),
35      '#dependency' => array('edit-options-validate-type' => array($this->id)),
36    );
37    if (!$options) {
38      $form[$this->_option_name('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' => 'admin/build/flags')) . '</p>';
39    }
40
41    $form[$this->_option_name('flag_test')] = array(
42      '#type' => 'select',
43      '#title' => t('Validate the @type only if', array('@type' => $this->flag_type)),
44      '#options' => $this->tests_options(),
45      '#default_value' => $this->_get_option('flag_test', 'flaggable'),
46      '#process' => array('views_process_dependency'),
47      '#dependency' => array('edit-options-validate-type' => array($this->id)),
48    );
49
50    // This validator supports the "multiple IDs" syntax. It may not be
51    // extremely useful, but similar validators do support this and it's a good
52    // thing to be compatible.
53    $form[$this->_option_name('flag_id_type')] = array(
54      '#type' => 'select',
55      '#title' => t('Argument type'),
56      '#options' => array(
57        'id' => t('ID'),
58        'ids' => t('IDs separated by , or +'),
59      ),
60      '#default_value' => $this->_get_option('flag_id_type', 'id'),
61      '#process' => array('views_process_dependency'),
62      '#dependency' => array('edit-options-validate-type' => array($this->id)),
63    );
64  }
65
66  /**
67   * Returns form #options for the flags. Returns empty array if no flags were
68   * found.
69   */
70  function flags_options() {
71    $flags = flag_get_flags($this->flag_type);
72    if (!$flags) {
73      return array();
74    }
75    else {
76      foreach ($flags as $flag) {
77        $options[$flag->name] = $flag->get_title();
78      }
79      $options['*relationship*'] = t('<em>Pick the first flag mentioned in the relationships.</em>');
80      return $options;
81    }
82  }
83
84  /**
85   * Validator arguments are stored in the argument object, not here, so we
86   * define a convenience method for fetching them.
87   */
88  function _get_option($option, $default) {
89    $option = $this->_option_name($option);
90    return isset($this->argument->options[$option]) ? $this->argument->options[$option] : $default;
91  }
92
93  function _option_name($option) {
94    // We must embed the flag type in the option name or else validators of
95    // different types will clash with each other. It's a trait of Views that all
96    // validators on the system get their settings lumped onto the argument.
97    // Examine the view's 'Export' output to understand.
98    return 'validate_argument_' . $this->flag_type . '_' . $option;
99  }
100
101  /**
102   * Declares all tests. This scheme makes it easy for derived classes to add
103   * and remove tests.
104   */
105  function tests_info($which = NULL) {
106    return array(
107      'flaggable' => array(
108        'title' => t('It is flaggable'),
109        'callback' => 'test_flaggable',
110      ),
111      'flagged' => array(
112        'title' => t('It is flagged at least once'),
113        'callback' => 'test_flagged',
114      ),
115      'flagged_by_current_user' => array(
116        'title' => t('It is flagged by the current user'),
117        'callback' => 'test_flagged_by_current_user',
118      ),
119    );
120  }
121
122  function tests_options() {
123    $options = array();
124    foreach ($this->tests_info() as $id => $info) {
125      $options[$id] = $info['title'];
126    }
127    return $options;
128  }
129
130  function get_flag() {
131    $flag_name = $this->_get_option('flag_name', '*relationship*');
132
133    if ($flag_name == '*relationship*') {
134      // Pick the first flag mentioned in the relationships.
135      foreach ($this->view->relationship as $id => $handler) {
136        // Note: we can't do $handler->field, because the relationship handler's 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->content_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->_get_option('flag_test', 'flaggable');
156    $id_type   = $this->_get_option('flag_id_type', 'id');
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);
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_content_id'));
201  }
202
203  function test_flagged($ids, $flag) {
204    // view_break_phrase() is guaranteed to return only integers, so this is SQL safe.
205    $flattened_ids = implode(',', $ids);
206    return $this->_test_by_sql("SELECT content_id FROM {flag_counts} WHERE fid = %d AND content_id IN ($flattened_ids) AND count > 0", array($flag->fid));
207  }
208
209  function test_flagged_by_current_user($ids, $flag) {
210    global $user;
211    if (!$user->uid) {
212      // Anonymous user
213      return FALSE;
214    }
215    $flattened_ids = implode(',', $ids);
216    return $this->_test_by_sql("SELECT content_id FROM {flag_content} WHERE fid = %d AND content_id IN ($flattened_ids) AND uid = %d", array($flag->fid, $user->uid));
217  }
218
219  // Helper: executes an SQL query and returns all the content_id's.
220  function _test_by_sql($sql, $args) {
221    $passed = array();
222    $result = db_query($sql, $args);
223    while ($row = db_fetch_object($result)) {
224      $passed[] = $row->content_id;
225    }
226    return $passed;
227  }
228}
229
Note: See TracBrowser for help on using the browser.