Projet

Général

Profil

Paste
Télécharger (13,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ldap / ldap_views / plugins / ldap_views_plugin_query_ldap.inc @ 91af538d

1
<?php
2

    
3
/**
4
 * @file
5
 * Defines the default query object which builds and execute a ldap query.
6
 */
7

    
8
/**
9
 *
10
 */
11
class ldap_views_plugin_query_ldap extends views_plugin_query {
12

    
13
  /**
14
   * The base dn for the LDAP search.
15
   */
16
  private $basedn = '';
17

    
18
  /**
19
   * A list of filters to apply to the LDAP search.
20
   */
21
  private $filter = [];
22

    
23
  /**
24
   * Builds the necessary info to execute the query.
25
   */
26
  public function build(&$view) {
27
    $view->init_pager($view);
28

    
29
    // Let the pager modify the query to add limits.
30
    $this->pager->query();
31
  }
32

    
33
  /**
34
   *
35
   */
36
  public function add_field($table, $field, $alias = '', $params = []) {
37
    // We check for this specifically because it gets a special alias.
38
    if ($table == $this->base_table && $field == $this->base_field && empty($alias)) {
39
      $alias = $this->base_field;
40
    }
41

    
42
    if (!$alias && $table) {
43
      $alias = $table . '_' . $field;
44
    }
45

    
46
    // Make sure an alias is assigned.
47
    $alias = $alias ? $alias : $field;
48

    
49
    // PostgreSQL truncates aliases to 63 characters: http://drupal.org/node/571548
50
    // We limit the length of the original alias up to 60 characters
51
    // to get a unique alias later if its have duplicates.
52
    $alias = drupal_substr($alias, 0, 60);
53

    
54
    // Create a field info array.
55
    $field_info = [
56
      'field' => $field,
57
      'table' => $table,
58
      'alias' => $alias,
59
    ] + $params;
60

    
61
    // Test to see if the field is actually the same or not. Due to
62
    // differing parameters changing the aggregation function, we need
63
    // to do some automatic alias collision detection:
64
    $base = $alias;
65
    $counter = 0;
66
    while (!empty($this->fields[$alias]) && $this->fields[$alias] != $field_info) {
67
      $field_info['alias'] = $alias = $base . '_' . ++$counter;
68
    }
69

    
70
    if (empty($this->fields[$alias])) {
71
      $this->fields[$alias] = $field_info;
72
    }
73

    
74
    return $alias;
75
  }
76

    
77
  /**
78
   *
79
   */
80
  public function add_orderby($table, $field, $order, $alias = '', $params = []) {
81
    $this->orderby[] = [
82
      'field' => $field,
83
      'direction' => drupal_strtoupper($order),
84
    ];
85
  }
86

    
87
  /**
88
   *
89
   */
90
  public function add_basedn($basedn) {
91
    $this->basedn = !empty($this->basedn) ? $this->basedn : $basedn;
92
  }
93

    
94
  /**
95
   *
96
   */
97
  public function add_filter($filter) {
98
    if (empty($filter)) {
99
      return;
100
    }
101
    $this->filter[] = $filter;
102
  }
103

    
104
  /**
105
   * Add a simple WHERE clause to the query. The caller is responsible for
106
   * ensuring that all fields are fully qualified (TABLE.FIELD) and that
107
   * the table already exists in the query.
108
   *
109
   * @param $group
110
   *   The WHERE group to add these to; groups are used to create AND/OR
111
   *   sections. Groups cannot be nested. Use 0 as the default group.
112
   *   If the group does not yet exist it will be created as an AND group.
113
   * @param $field
114
   *   The name of the field to check.
115
   * @param $value
116
   *   The value to test the field against. In most cases, this is a scalar. For more
117
   *   complex options, it is an array. The meaning of each element in the array is
118
   *   dependent on the $operator.
119
   * @param $operator
120
   *   The comparison operator, such as =, <, or >=. It also accepts more complex
121
   *   options such as IN, LIKE, or BETWEEN. Defaults to IN if $value is an array
122
   *   = otherwise. If $field is a string you have to use 'formula' here.
123
   *
124
   * @see QueryConditionInterface::condition()
125
   */
126
  public function add_where($group, $field, $value = NULL, $operator = NULL) {
127
    // Ensure all variants of 0 are actually 0. Thus '', 0 and NULL are all
128
    // the default group.
129
    if (empty($group)) {
130
      $group = 0;
131
    }
132

    
133
    // Check for a group.
134
    if (!isset($this->where[$group])) {
135
      $this->set_where_group('AND', $group);
136
    }
137

    
138
    $this->where[$group]['conditions'][] = [
139
      'field' => $field,
140
      'value' => $value,
141
      'operator' => ltrim($operator, '!'),
142
      'negate' => drupal_substr($operator, 0, 1) == '!',
143
    ];
144
  }
145

    
146
  /**
147
   * Construct the filter.
148
   *
149
   * @param $where
150
   *   'where' or 'having'.
151
   *
152
   * @return string
153
   */
154
  public function build_condition() {
155
    $operator = ['AND' => '&', 'OR' => '|'];
156
    $main_group = '';
157
    if (!isset($this->where)) {
158
      // Initialize where clause if not set.
159
      $this->where = [];
160
    }
161
    foreach ($this->where as $group => $info) {
162
      if (!empty($info['conditions'])) {
163
        $sub_group = '';
164
        foreach ($info['conditions'] as $key => $clause) {
165
          $item       = '(' . $clause['field'] . $clause['operator'] . $clause['value'] . ')';
166
          $sub_group .= $clause['negate'] ? "(!$item)" : $item;
167
        }
168
        $main_group .= count($info['conditions']) <= 1 ? $sub_group : '(' . $operator[$info['type']] . $sub_group . ')';
169
      }
170
    }
171
    return count($this->where) <= 1 ? $main_group : '(' . $operator[$this->group_operator] . $main_group . ')';
172
  }
173

    
174
  /**
175
   *
176
   */
177
  public function build_ldap_basedn($basedn) {
178
    return !empty($this->basedn) ? [$this->basedn] : $basedn;
179
  }
180

    
181
  /**
182
   *
183
   */
184
  public function build_contextual_filter() {
185
    $contextual_filter = '';
186
    foreach ($this->filter as $condition) {
187
      $contextual_filter .= drupal_substr($condition, 0, 1) != '(' ? "($condition)" : $condition;
188
    }
189
    return $contextual_filter;
190
  }
191

    
192
  /**
193
   *
194
   */
195
  public function build_ldap_filter($filter) {
196
    $condition     = $this->build_condition();
197
    $contextual    = $this->build_contextual_filter();
198
    $search_filter = !empty($contextual) && !empty($condition) ? '(&' . $condition . $contextual . ')' : $condition . $contextual;
199
    //if both ldap views filters & ldap views query filter exist, combine them
200
    //if the ldap views filter exist, use that
201
    //else, use ldap query filter
202
    if (!empty($search_filter) && !empty($filter)) {
203
       return '(&' . $search_filter . $filter . ')';
204
    } elseif (!empty($search_filter)) {
205
       return $search_filter;
206
    } else {
207
       return $filter;
208
    }
209
  }
210

    
211
  /**
212
   * Ensure a table exists in the queue; if it already exists it won't
213
   * do anything, but if it doesn't it will add the table queue. It will ensure
214
   * a path leads back to the relationship table.
215
   *
216
   * @param $table
217
   *   The unaliased name of the table to ensure.
218
   * @param $relationship
219
   *   The relationship to ensure the table links to. Each relationship will
220
   *   get a unique instance of the table being added. If not specified,
221
   *   will be the primary table.
222
   * @param $join
223
   *   A views_join object (or derived object) to join the alias in.
224
   *
225
   * @return
226
   *   The alias used to refer to this specific table, or NULL if the table
227
   *   cannot be ensured.
228
   */
229
  public function ensure_table($table, $relationship = NULL, $join = NULL) {
230
    return $table;
231
  }
232

    
233
  /**
234
   * Executes the query and fills the associated view object with according
235
   * values.
236
   *
237
   * Values to set: $view->result, $view->total_rows, $view->execute_time,
238
   * $view->pager['current_page'].
239
   *
240
   * $view->result should contain an array of objects.
241
   */
242
  public function execute(&$view) {
243
    $start       = microtime(TRUE);
244
    $entries     = [];
245
    $num_entries = 0;
246

    
247
    if (empty($this->options['qid'])) {
248
      watchdog('ldap_views', 'Query definition is empty');
249
      return;
250
    }
251
    foreach ($this->fields as $field) {
252
      $attributes[$field['alias']] = $field['field'];
253
      $field_alias[$field['alias']] = drupal_strtolower($field['field']);
254
    }
255

    
256
    $ldap_data   = new LdapQuery(ldap_views_get_qid($view));
257
    $ldap_server = new LdapServer($ldap_data->sid);
258
    $ldap_server->connect();
259
    $ldap_server->bind();
260
    // TODO: Can't use sizelimit if it must be ordered || cache?
261
    // $ldap_server->search() hasn't orderby (ldap_sort)
262
    // But we can't use ldap_sort because there's no DESC option.
263
    foreach ($this->build_ldap_basedn($ldap_data->baseDn) as $basedn) {
264

    
265
      $result = $ldap_server->search($basedn, $this->build_ldap_filter($ldap_data->filter), array_values($attributes), 0, $ldap_data->sizelimit, $ldap_data->timelimit, $ldap_data->deref, $ldap_data->scope);
266
      // ldap_sort can't be used because there's no DESC option
267
      // Not an error.
268
      if ($result !== FALSE) {
269
        $entries = array_merge($entries, $result);
270
        $num_entries += $result['count'];
271
        unset($result['count']);
272
      }
273
    }
274
    if (property_exists($view->query, 'limit')) {
275
      $limit = $view->query->limit;
276
    }
277
    $offset      = property_exists($view->query, 'offset') ? $view->query->offset : 0;
278
    $result      = [];
279
    $sort_fields = [];
280
    if (!empty($this->orderby)) {
281
      foreach ($this->orderby as $orderby) {
282
        $sort_fields[drupal_strtolower($orderby['field'])]['direction'] = $orderby['direction'];
283
        $sort_fields[drupal_strtolower($orderby['field'])]['data']      = [];
284
      }
285

    
286
    }
287

    
288
    foreach ($entries as $key => &$entry) {
289
      if (isset($entry['jpegphoto'])) {
290
        $entry['jpegphoto'][0] = '<img src="data:image/jpeg;base64,' . base64_encode($entry['jpegphoto'][0]) . '" alt="photo" />';
291
      }
292
      if (isset($entry['thumbnailphoto'])) {
293
        $entry['thumbnailphoto'][0] = '<img src="data:image/jpeg;base64,' . base64_encode($entry['thumbnailphoto'][0]) . '" alt="photo" />';
294
      }
295
      foreach ($view->field as $field) {
296
        if (!isset($field_alias[$field->field_alias])) {
297
          continue;
298
        }
299
        $alias = $field_alias[$field->field_alias];
300
        if (is_array($entry) && array_key_exists($alias, $entry)) {
301
          if (is_array($entry[$alias])) {
302
            switch ($field->options['multivalue']) {
303
              case 'v-all':
304
                // Remove 'count' index.
305
                unset($entry[$alias]['count']);
306
                $entry[$alias] = implode($field->options['value_separator'], $entry[$alias]);
307
                break;
308

    
309
              case 'v-count':
310
                $entry[$alias] = $entry[$alias]['count'];
311
                break;
312

    
313
              case 'v-index':
314
                $index = $field->options['index_value'] >= 0 ? intval($field->options['index_value']) : $entry[$alias]['count'] + $field->options['index_value'];
315
                $entry[$alias] = array_key_exists($index, $entry[$alias]) ? $entry[$alias][$index] :
316
                                                                            $entry[$alias][0];
317
                break;
318
            }
319
          }
320
          // Order criteria
321
          // If the field with alias $alias has a corresponding entry in $sort_fields, copy its value into the data key of $sort_fields for later sorting.
322
          if (array_key_exists($alias, $sort_fields)) {
323
            $sort_fields[$alias]['data'][$key] = $entry[$alias];
324
          }
325
        }
326
      }
327
    }
328
    if (!empty($this->orderby) && !empty($entries)) {
329
      $params = [];
330
      // In PHP 5.3 every parameter in the array has to be a reference when calling array_multisort() with call_user_func_array().
331
      $asc = SORT_ASC;
332
      $desc = SORT_DESC;
333
      foreach ($sort_fields as &$field) {
334
        $params[] = &$field['data'];
335
        if (drupal_strtoupper($field['direction']) == 'ASC') {
336
          $params[] = &$asc;
337
        }
338
        else {
339
          $params[] = &$desc;
340
        }
341
      }
342
      $params[] = &$entries;
343

    
344
      // Some LDAP setups output a 'count' variable in the array, which changes
345
      // the array size; temporarily remove it, sort the arrays, and then put it
346
      // back.
347
      if (array_key_exists('count', $entries)) {
348
        // Remove the count variable.
349
        $countValue = $entries['count'];
350
        unset($entries['count']);
351
        $params[] = &$entries;
352
        call_user_func_array('array_multisort', $params);
353
        $params['count'] = $countValue;
354
      }
355
      else {
356
        $params[] = &$entries;
357
        call_user_func_array('array_multisort', $params);
358
      }
359
    }
360

    
361
    for ($i = 0; (!isset($limit) || $i < $limit) && $offset + $i < $num_entries; $i++) {
362
      $row = [];
363
      $entry = &$entries[$offset + $i];
364
      foreach ($view->field as $field) {
365
        if (!isset($field_alias[$field->field_alias])) {
366
          continue;
367
        }
368
        if (array_key_exists($field_alias[$field->field_alias], $entry)) {
369
          $row[$field->field_alias] = $entry[$field_alias[$field->field_alias]];
370
        }
371
      }
372
      $result[] = $row;
373
    }
374

    
375
    $view->result                    = $result;
376
    $view->total_rows                = $num_entries;
377
    $view->execute_time              = microtime(TRUE) - $start;
378
    $view->query->pager->total_items = $num_entries;
379
    $view->query->pager->update_page_info();
380

    
381
  }
382

    
383
  /**
384
   *
385
   */
386
  public function option_definition() {
387
    $options = parent::option_definition();
388
    $options['qid'] = ['default' => ''];
389

    
390
    return $options;
391
  }
392

    
393
  /**
394
   *
395
   */
396
  public function options_form(&$form, &$form_state) {
397
    $queries = [];
398
    $queries['all'] = LdapQueryAdmin::getLdapQueryObjects();
399

    
400
    foreach ($queries['all'] as $_sid => $ldap_query) {
401
      if ($ldap_query->status == 1) {
402
        $options[$ldap_query->qid] = $ldap_query->name;
403
      }
404
    }
405
    $form['qid'] = [
406
      '#type' => 'select',
407
      '#title' => t('LDAP Search'),
408
      '#options' => $options,
409
      '#default_value' => $this->options['qid'],
410
      '#description' => t("The LDAP server to query."),
411
    ];
412
  }
413

    
414
  /**
415
   * Let modules modify the query just prior to finalizing it.
416
   */
417
  public function alter(&$view) {
418
    foreach (module_implements('views_query_alter') as $module) {
419
      $function = $module . '_views_query_alter';
420
      $function($view, $this);
421
    }
422
  }
423

    
424
}