1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* @file
|
5
|
* Defines the default query object which builds and execute a ldap query
|
6
|
*/
|
7
|
|
8
|
class ldap_views_plugin_query_ldap extends views_plugin_query {
|
9
|
|
10
|
/**
|
11
|
* The base dn for the LDAP search
|
12
|
*/
|
13
|
private $basedn = '';
|
14
|
|
15
|
/**
|
16
|
* A list of filters to apply to the LDAP search
|
17
|
*/
|
18
|
private $filter = array();
|
19
|
|
20
|
/**
|
21
|
* Builds the necessary info to execute the query.
|
22
|
*/
|
23
|
function build(&$view) {
|
24
|
$view->init_pager($view);
|
25
|
|
26
|
// Let the pager modify the query to add limits.
|
27
|
$this->pager->query();
|
28
|
}
|
29
|
|
30
|
function add_field($table, $field, $alias = '', $params = array()) {
|
31
|
// We check for this specifically because it gets a special alias.
|
32
|
if ($table == $this->base_table && $field == $this->base_field && empty($alias)) {
|
33
|
$alias = $this->base_field;
|
34
|
}
|
35
|
|
36
|
if (!$alias && $table) {
|
37
|
$alias = $table . '_' . $field;
|
38
|
}
|
39
|
|
40
|
// Make sure an alias is assigned
|
41
|
$alias = $alias ? $alias : $field;
|
42
|
|
43
|
// PostgreSQL truncates aliases to 63 characters: http://drupal.org/node/571548
|
44
|
|
45
|
// We limit the length of the original alias up to 60 characters
|
46
|
// to get a unique alias later if its have duplicates
|
47
|
$alias = drupal_substr($alias, 0, 60);
|
48
|
|
49
|
// Create a field info array.
|
50
|
$field_info = array(
|
51
|
'field' => $field,
|
52
|
'table' => $table,
|
53
|
'alias' => $alias,
|
54
|
) + $params;
|
55
|
|
56
|
// Test to see if the field is actually the same or not. Due to
|
57
|
// differing parameters changing the aggregation function, we need
|
58
|
// to do some automatic alias collision detection:
|
59
|
$base = $alias;
|
60
|
$counter = 0;
|
61
|
while (!empty($this->fields[$alias]) && $this->fields[$alias] != $field_info) {
|
62
|
$field_info['alias'] = $alias = $base . '_' . ++$counter;
|
63
|
}
|
64
|
|
65
|
if (empty($this->fields[$alias])) {
|
66
|
$this->fields[$alias] = $field_info;
|
67
|
}
|
68
|
|
69
|
return $alias;
|
70
|
}
|
71
|
|
72
|
function add_orderby($table, $field, $order, $alias = '', $params = array()) {
|
73
|
$this->orderby[] = array(
|
74
|
'field' => $field,
|
75
|
'direction' => drupal_strtoupper($order)
|
76
|
);
|
77
|
}
|
78
|
|
79
|
function add_basedn($basedn) {
|
80
|
$this->basedn = !empty($this->basedn) ? $this->basedn : $basedn;
|
81
|
}
|
82
|
|
83
|
function add_filter($filter) {
|
84
|
if (empty($filter)) {
|
85
|
return;
|
86
|
}
|
87
|
$this->filter[] = $filter;
|
88
|
}
|
89
|
|
90
|
/**
|
91
|
* Add a simple WHERE clause to the query. The caller is responsible for
|
92
|
* ensuring that all fields are fully qualified (TABLE.FIELD) and that
|
93
|
* the table already exists in the query.
|
94
|
*
|
95
|
* @param $group
|
96
|
* The WHERE group to add these to; groups are used to create AND/OR
|
97
|
* sections. Groups cannot be nested. Use 0 as the default group.
|
98
|
* If the group does not yet exist it will be created as an AND group.
|
99
|
* @param $field
|
100
|
* The name of the field to check.
|
101
|
* @param $value
|
102
|
* The value to test the field against. In most cases, this is a scalar. For more
|
103
|
* complex options, it is an array. The meaning of each element in the array is
|
104
|
* dependent on the $operator.
|
105
|
* @param $operator
|
106
|
* The comparison operator, such as =, <, or >=. It also accepts more complex
|
107
|
* options such as IN, LIKE, or BETWEEN. Defaults to IN if $value is an array
|
108
|
* = otherwise. If $field is a string you have to use 'formula' here.
|
109
|
*
|
110
|
* @see QueryConditionInterface::condition()
|
111
|
*/
|
112
|
function add_where($group, $field, $value = NULL, $operator = NULL) {
|
113
|
// Ensure all variants of 0 are actually 0. Thus '', 0 and NULL are all
|
114
|
// the default group.
|
115
|
if (empty($group)) {
|
116
|
$group = 0;
|
117
|
}
|
118
|
|
119
|
// Check for a group.
|
120
|
if (!isset($this->where[$group])) {
|
121
|
$this->set_where_group('AND', $group);
|
122
|
}
|
123
|
|
124
|
$this->where[$group]['conditions'][] = array(
|
125
|
'field' => $field,
|
126
|
'value' => $value,
|
127
|
'operator' => ltrim($operator, '!'),
|
128
|
'negate' => drupal_substr($operator, 0, 1) == '!',
|
129
|
);
|
130
|
}
|
131
|
|
132
|
/**
|
133
|
* Construct the filter
|
134
|
*
|
135
|
* @param $where
|
136
|
* 'where' or 'having'.
|
137
|
*/
|
138
|
function build_condition() {
|
139
|
$operator = array('AND' => '&', 'OR' => '|');
|
140
|
$main_group = '';
|
141
|
if (!isset($this->where)) {
|
142
|
$this->where = array(); // Initialize where clause if not set
|
143
|
}
|
144
|
foreach ($this->where as $group => $info) {
|
145
|
if (!empty($info['conditions'])) {
|
146
|
$sub_group = '';
|
147
|
foreach ($info['conditions'] as $key => $clause) {
|
148
|
$item = '(' . $clause['field'] . $clause['operator'] . $clause['value'] . ')';
|
149
|
$sub_group .= $clause['negate'] ? "(!$item)" : $item;
|
150
|
}
|
151
|
$main_group .= count($info['conditions']) <= 1 ? $sub_group : '(' . $operator[$info['type']] . $sub_group . ')';
|
152
|
}
|
153
|
}
|
154
|
return count($this->where) <= 1 ? $main_group : '(' . $operator[$this->group_operator] . $main_group . ')';
|
155
|
}
|
156
|
|
157
|
function build_ldap_basedn($basedn) {
|
158
|
return !empty($this->basedn) ? array($this->basedn) : $basedn;
|
159
|
}
|
160
|
|
161
|
function build_contextual_filter() {
|
162
|
$contextual_filter = '';
|
163
|
foreach ($this->filter as $condition) {
|
164
|
$contextual_filter .= drupal_substr($condition, 0, 1) != '(' ? "($condition)" : $condition;
|
165
|
}
|
166
|
return $contextual_filter;
|
167
|
}
|
168
|
|
169
|
function build_ldap_filter($filter) {
|
170
|
$condition = $this->build_condition();
|
171
|
$contextual = $this->build_contextual_filter();
|
172
|
$search_filter = !empty($contextual) && !empty($condition) ? '(&' . $condition . $contextual . ')' : $condition . $contextual;
|
173
|
return !empty($search_filter) ? $search_filter : $filter;
|
174
|
}
|
175
|
|
176
|
/**
|
177
|
* Ensure a table exists in the queue; if it already exists it won't
|
178
|
* do anything, but if it doesn't it will add the table queue. It will ensure
|
179
|
* a path leads back to the relationship table.
|
180
|
*
|
181
|
* @param $table
|
182
|
* The unaliased name of the table to ensure.
|
183
|
* @param $relationship
|
184
|
* The relationship to ensure the table links to. Each relationship will
|
185
|
* get a unique instance of the table being added. If not specified,
|
186
|
* will be the primary table.
|
187
|
* @param $join
|
188
|
* A views_join object (or derived object) to join the alias in.
|
189
|
*
|
190
|
* @return
|
191
|
* The alias used to refer to this specific table, or NULL if the table
|
192
|
* cannot be ensured.
|
193
|
*/
|
194
|
function ensure_table($table, $relationship = NULL, $join = NULL) {
|
195
|
return $table;
|
196
|
}
|
197
|
|
198
|
/**
|
199
|
* Executes the query and fills the associated view object with according
|
200
|
* values.
|
201
|
*
|
202
|
* Values to set: $view->result, $view->total_rows, $view->execute_time,
|
203
|
* $view->pager['current_page'].
|
204
|
*
|
205
|
* $view->result should contain an array of objects.
|
206
|
*/
|
207
|
function execute(&$view) {
|
208
|
$start = microtime(TRUE);
|
209
|
$entries = array();
|
210
|
$num_entries = 0;
|
211
|
|
212
|
if (empty($this->options['qid'])) {
|
213
|
watchdog('ldap_views', 'Query definition is empty');
|
214
|
return;
|
215
|
}
|
216
|
foreach ($this->fields as $field) {
|
217
|
$attributes[$field['alias']] = $field['field'];
|
218
|
$field_alias[$field['alias']] = drupal_strtolower($field['field']);
|
219
|
}
|
220
|
|
221
|
$ldap_data = new LdapQuery(ldap_views_get_qid($view));
|
222
|
$ldap_server = new LdapServer($ldap_data->sid);
|
223
|
$ldap_server->connect();
|
224
|
$ldap_server->bind();
|
225
|
// TODO: Can't use sizelimit if it must be ordered || cache?
|
226
|
// $ldap_server->search() hasn't orderby (ldap_sort)
|
227
|
// But we can't use ldap_sort because there's no DESC option
|
228
|
foreach ($this->build_ldap_basedn($ldap_data->baseDn) as $basedn) {
|
229
|
|
230
|
$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);
|
231
|
/**
|
232
|
// ldap_sort can't be used because there's no DESC option
|
233
|
if (!empty($this->orderby)) {
|
234
|
// Array reverse, because the most specific are first - PHP works the opposite way of SQL.
|
235
|
foreach (array_reverse($this->orderby) as $field) {
|
236
|
@ldap_sort($ldap_server->connection, $result, $field['field']);
|
237
|
}
|
238
|
}
|
239
|
*/
|
240
|
if ($result !== FALSE) { // not an error
|
241
|
$entries = array_merge($entries, $result);
|
242
|
$num_entries += $result['count'];
|
243
|
unset($result['count']);
|
244
|
}
|
245
|
}
|
246
|
if (property_exists($view->query, 'limit')) {
|
247
|
$limit = $view->query->limit;
|
248
|
}
|
249
|
$offset = property_exists($view->query, 'offset') ? $view->query->offset : 0;
|
250
|
$result = array();
|
251
|
$sort_fields = array();
|
252
|
if (!empty($this->orderby)) {
|
253
|
foreach ($this->orderby as $orderby) {
|
254
|
$sort_fields[drupal_strtolower($orderby['field'])]['direction'] = $orderby['direction'];
|
255
|
$sort_fields[drupal_strtolower($orderby['field'])]['data'] = array();
|
256
|
}
|
257
|
|
258
|
}
|
259
|
|
260
|
foreach ($entries as $key => &$entry) {
|
261
|
if (isset($entry['jpegphoto'])) {
|
262
|
$entry['jpegphoto'][0] = '<img src="data:image/jpeg;base64,' . base64_encode($entry['jpegphoto'][0]) . '" alt="photo" />';
|
263
|
}
|
264
|
if (isset($entry['thumbnailphoto'])) {
|
265
|
$entry['thumbnailphoto'][0] = '<img src="data:image/jpeg;base64,' . base64_encode($entry['thumbnailphoto'][0]) . '" alt="photo" />';
|
266
|
}
|
267
|
foreach ($view->field as $field) {
|
268
|
if (! isset($field_alias[$field->field_alias])) {
|
269
|
continue;
|
270
|
}
|
271
|
$alias = $field_alias[$field->field_alias];
|
272
|
if (is_array($entry) && array_key_exists($alias, $entry)) {
|
273
|
if (is_array($entry[$alias])) {
|
274
|
switch ($field->options['multivalue']) {
|
275
|
case 'v-all':
|
276
|
// remove 'count' index
|
277
|
unset($entry[$alias]['count']);
|
278
|
$entry[$alias] = implode($field->options['value_separator'], $entry[$alias]);
|
279
|
break;
|
280
|
case 'v-count':
|
281
|
$entry[$alias] = $entry[$alias]['count'];
|
282
|
break;
|
283
|
case 'v-index':
|
284
|
$index = $field->options['index_value'] >= 0 ? intval($field->options['index_value']) : $entry[$alias]['count'] + $field->options['index_value'];
|
285
|
$entry[$alias] = array_key_exists($index, $entry[$alias]) ? $entry[$alias][$index] :
|
286
|
$entry[$alias][0];
|
287
|
break;
|
288
|
}
|
289
|
}
|
290
|
// order criteria
|
291
|
//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.
|
292
|
if (array_key_exists($alias, $sort_fields)) {
|
293
|
$sort_fields[$alias]['data'][$key] = $entry[$alias];
|
294
|
}
|
295
|
}
|
296
|
}
|
297
|
}
|
298
|
if (!empty($this->orderby) && !empty($entries)) {
|
299
|
$params = array();
|
300
|
// In PHP 5.3 every parameter in the array has to be a reference when calling array_multisort() with call_user_func_array().
|
301
|
$asc = SORT_ASC;
|
302
|
$desc = SORT_DESC;
|
303
|
foreach ($sort_fields as &$field) {
|
304
|
$params[] = &$field['data'];
|
305
|
if (drupal_strtoupper($field['direction']) == 'ASC') {
|
306
|
$params[] = &$asc;
|
307
|
}
|
308
|
else {
|
309
|
$params[] = &$desc;
|
310
|
}
|
311
|
}
|
312
|
$params[] = &$entries;
|
313
|
|
314
|
// Some LDAP setups output a 'count' variable in the array, which changes the array size;
|
315
|
// temporarily remove it, sort the arrays, and then put it back.
|
316
|
if (array_key_exists('count', $entries)) {
|
317
|
$countValue = $entries['count']; // remove the count variable
|
318
|
unset($entries['count']);
|
319
|
$params[] = &$entries;
|
320
|
call_user_func_array('array_multisort', $params);
|
321
|
$params['count'] = $countValue;
|
322
|
}
|
323
|
else {
|
324
|
$params[] = &$entries;
|
325
|
call_user_func_array('array_multisort', $params);
|
326
|
}
|
327
|
}
|
328
|
|
329
|
for ($i = 0; (!isset($limit) || $i < $limit) && $offset + $i < $num_entries; $i++) {
|
330
|
$row = array();
|
331
|
$entry = &$entries[$offset + $i];
|
332
|
foreach ($view->field as $field) {
|
333
|
if (! isset($field_alias[$field->field_alias])) {
|
334
|
continue;
|
335
|
}
|
336
|
if (array_key_exists($field_alias[$field->field_alias], $entry)) {
|
337
|
$row[$field->field_alias] = $entry[$field_alias[$field->field_alias]];
|
338
|
}
|
339
|
}
|
340
|
$result[] = $row;
|
341
|
}
|
342
|
|
343
|
$view->result = $result;
|
344
|
$view->total_rows = $num_entries;
|
345
|
$view->execute_time = microtime(TRUE) - $start;
|
346
|
$view->query->pager->total_items = $num_entries;
|
347
|
$view->query->pager->update_page_info();
|
348
|
|
349
|
}
|
350
|
|
351
|
function option_definition() {
|
352
|
$options = parent::option_definition();
|
353
|
$options['qid'] = array('default' => '');
|
354
|
|
355
|
return $options;
|
356
|
}
|
357
|
|
358
|
function options_form(&$form, &$form_state) {
|
359
|
/**
|
360
|
$ldap_data = entity_load('ldap_data', FALSE);
|
361
|
$options = array();
|
362
|
foreach ($ldap_data as $data) {
|
363
|
$options[$data->qid] = $data->name;
|
364
|
}
|
365
|
*/
|
366
|
$queries = array();
|
367
|
$queries['all'] = LdapQueryAdmin::getLdapQueryObjects();
|
368
|
|
369
|
foreach ($queries['all'] as $_sid => $ldap_query) {
|
370
|
if ($ldap_query->status == 1) {
|
371
|
//$queries['enabled'][$_qid] = $ldap_query;
|
372
|
$options[$ldap_query->qid] = $ldap_query->name;
|
373
|
}
|
374
|
}
|
375
|
// ******************************************************
|
376
|
$form['qid'] = array(
|
377
|
'#type' => 'select',
|
378
|
'#title' => t('LDAP Search'),
|
379
|
'#options' => $options,
|
380
|
'#default_value' => $this->options['qid'],
|
381
|
'#description' => t("The LDAP server to query."),
|
382
|
);
|
383
|
}
|
384
|
|
385
|
|
386
|
/**
|
387
|
* Let modules modify the query just prior to finalizing it.
|
388
|
*/
|
389
|
function alter(&$view) {
|
390
|
foreach (module_implements('views_query_alter') as $module) {
|
391
|
$function = $module . '_views_query_alter';
|
392
|
$function($view, $this);
|
393
|
}
|
394
|
}
|
395
|
|
396
|
/* Only when adding dynamic fields in ldap_views_views_data_alter()
|
397
|
function options_submit(&$form, &$form_state) {
|
398
|
parent::options_submit(&$form, &$form_state);
|
399
|
if ($form_state['values']['query']['options']['qid'] != $form_state['view']->query->options['qid']) {
|
400
|
views_invalidate_cache();
|
401
|
}
|
402
|
}
|
403
|
*/
|
404
|
}
|