1 |
85ad3d82
|
Assos Assos
|
<?php
|
2 |
|
|
|
3 |
|
|
/**
|
4 |
|
|
* @file VBO action to modify entity values (properties and fields).
|
5 |
|
|
*/
|
6 |
|
|
|
7 |
|
|
// Specifies that all available values should be shown to the user for editing.
|
8 |
|
|
define('VBO_MODIFY_ACTION_ALL', '_all_');
|
9 |
|
|
|
10 |
|
|
function views_bulk_operations_modify_action_info() {
|
11 |
|
|
return array('views_bulk_operations_modify_action' => array(
|
12 |
|
|
'type' => 'entity',
|
13 |
|
|
'label' => t('Modify entity values'),
|
14 |
|
|
'behavior' => array('changes_property'),
|
15 |
|
|
// This action only works when invoked through VBO. That's why it's
|
16 |
|
|
// declared as non-configurable to prevent it from being shown in the
|
17 |
|
|
// "Create an advanced action" dropdown on admin/config/system/actions.
|
18 |
|
|
'configurable' => FALSE,
|
19 |
|
|
'vbo_configurable' => TRUE,
|
20 |
|
|
'triggers' => array('any'),
|
21 |
|
|
));
|
22 |
|
|
}
|
23 |
|
|
|
24 |
|
|
/**
|
25 |
|
|
* Action function.
|
26 |
|
|
*
|
27 |
|
|
* Goes through new values and uses them to modify the passed entity by either
|
28 |
|
|
* replacing the existing values, or appending to them (based on user input).
|
29 |
|
|
*/
|
30 |
|
|
function views_bulk_operations_modify_action($entity, $context) {
|
31 |
|
|
list(,,$bundle_name) = entity_extract_ids($context['entity_type'], $entity);
|
32 |
|
|
// Handle Field API fields.
|
33 |
|
|
if (!empty($context['selected']['bundle_' . $bundle_name])) {
|
34 |
|
|
// The pseudo entity is cloned so that changes to it don't get carried
|
35 |
|
|
// over to the next execution.
|
36 |
|
|
$pseudo_entity = clone $context['entities'][$bundle_name];
|
37 |
|
|
foreach ($context['selected']['bundle_' . $bundle_name] as $key) {
|
38 |
|
|
// Get this field's language. We can just pull it from the pseudo entity
|
39 |
|
|
// as it was created using field_attach_form and entity_language so it's
|
40 |
|
|
// already been figured out if this field is translatable or not and
|
41 |
|
|
// applied the appropriate language code to the field
|
42 |
|
|
$language = key($pseudo_entity->{$key});
|
43 |
|
|
// Replace any tokens that might exist in the field columns.
|
44 |
|
|
foreach ($pseudo_entity->{$key}[$language] as $delta => &$item) {
|
45 |
|
|
foreach ($item as $column => $value) {
|
46 |
|
|
if (is_string($value)) {
|
47 |
|
|
$item[$column] = token_replace($value, array($context['entity_type'] => $entity), array('sanitize' => FALSE));
|
48 |
|
|
}
|
49 |
|
|
}
|
50 |
|
|
}
|
51 |
|
|
|
52 |
|
|
if (in_array($key, $context['append']['bundle_' . $bundle_name]) && !empty($entity->$key)) {
|
53 |
|
|
$entity->{$key}[$language] = array_merge($entity->{$key}[$language], $pseudo_entity->{$key}[$language]);
|
54 |
|
|
|
55 |
|
|
// Check if we breached cardinality, and notify the user.
|
56 |
|
|
$field_info = field_info_field($key);
|
57 |
|
|
$field_count = count($entity->{$key}[$language]);
|
58 |
|
|
if ($field_info['cardinality'] != FIELD_CARDINALITY_UNLIMITED && $field_count > $field_info['cardinality']) {
|
59 |
|
|
$entity_label = entity_label($context['entity_type'], $entity);
|
60 |
|
|
$warning = t('Tried to set !field_count values for field !field_name that supports a maximum of !cardinality.',
|
61 |
|
|
array('!field_count' => $field_count,
|
62 |
|
|
'!field_name' => $field_info['field_name'],
|
63 |
|
|
'!cardinality' => $field_info['cardinality']));
|
64 |
|
|
drupal_set_message($warning, 'warning', FALSE);
|
65 |
|
|
}
|
66 |
|
|
|
67 |
|
|
// Prevent storing duplicate references.
|
68 |
|
|
if (strpos($field_info['type'], 'reference') !== FALSE) {
|
69 |
|
|
$entity->{$key}[$language] = array_unique($entity->{$key}[LANGUAGE_NONE], SORT_REGULAR);
|
70 |
|
|
}
|
71 |
|
|
}
|
72 |
|
|
else {
|
73 |
|
|
$entity->{$key}[$language] = $pseudo_entity->{$key}[$language];
|
74 |
|
|
}
|
75 |
|
|
}
|
76 |
|
|
}
|
77 |
|
|
|
78 |
|
|
// Handle properties.
|
79 |
|
|
if (!empty($context['selected']['properties'])) {
|
80 |
|
|
// Use the wrapper to set property values, since some properties need
|
81 |
|
|
// additional massaging by their setter callbacks.
|
82 |
|
|
// The wrapper will automatically modify $entity itself.
|
83 |
|
|
$wrapper = entity_metadata_wrapper($context['entity_type'], $entity);
|
84 |
|
|
foreach ($context['selected']['properties'] as $key) {
|
85 |
9df8b457
|
Assos Assos
|
if (!$wrapper->$key->access('update')) {
|
86 |
|
|
// No access.
|
87 |
|
|
continue;
|
88 |
|
|
}
|
89 |
|
|
|
90 |
85ad3d82
|
Assos Assos
|
if (in_array($key, $context['append']['properties'])) {
|
91 |
|
|
$old_values = $wrapper->$key->value();
|
92 |
|
|
$wrapper->$key->set($context['properties'][$key]);
|
93 |
|
|
$new_values = $wrapper->{$key}->value();
|
94 |
|
|
$all_values = array_merge($old_values, $new_values);
|
95 |
|
|
$wrapper->$key->set($all_values);
|
96 |
|
|
}
|
97 |
|
|
else {
|
98 |
|
|
$value = $context['properties'][$key];
|
99 |
|
|
if (is_string($value)) {
|
100 |
|
|
$value = token_replace($value, array($context['entity_type'] => $entity), array('sanitize' => FALSE));
|
101 |
|
|
}
|
102 |
|
|
$wrapper->$key->set($value);
|
103 |
|
|
}
|
104 |
|
|
}
|
105 |
|
|
}
|
106 |
|
|
}
|
107 |
|
|
|
108 |
|
|
/**
|
109 |
|
|
* Action form function.
|
110 |
|
|
*
|
111 |
|
|
* Displays form elements for properties acquired through Entity Metadata
|
112 |
|
|
* (hook_entity_property_info()), as well as field widgets for each
|
113 |
|
|
* entity bundle, as provided by field_attach_form().
|
114 |
|
|
*/
|
115 |
|
|
function views_bulk_operations_modify_action_form($context, &$form_state) {
|
116 |
|
|
// This action form uses admin-provided settings. If they were not set, pull the defaults now.
|
117 |
|
|
if (!isset($context['settings'])) {
|
118 |
|
|
$context['settings'] = views_bulk_operations_modify_action_views_bulk_operations_form_options();
|
119 |
|
|
}
|
120 |
|
|
|
121 |
|
|
$form_state['entity_type'] = $entity_type = $context['entity_type'];
|
122 |
|
|
// For Field API integration to work, a pseudo-entity is constructed for each
|
123 |
|
|
// bundle that has fields available for editing.
|
124 |
|
|
// The entities then get passed to Field API functions
|
125 |
|
|
// (field_attach_form(), field_attach_form_validate(), field_attach_submit()),
|
126 |
|
|
// and filled with form data.
|
127 |
|
|
// After submit, the pseudo-entities get passed to the actual action
|
128 |
|
|
// (views_bulk_operations_modify_action()) which copies the data from the
|
129 |
|
|
// relevant pseudo-entity constructed here to the actual entity being modified.
|
130 |
|
|
$form_state['entities'] = array();
|
131 |
|
|
|
132 |
|
|
$info = entity_get_info($entity_type);
|
133 |
|
|
$properties = _views_bulk_operations_modify_action_get_properties($entity_type, $context['settings']['display_values']);
|
134 |
|
|
$bundles = _views_bulk_operations_modify_action_get_bundles($entity_type, $context);
|
135 |
|
|
|
136 |
|
|
$form['#attached']['css'][] = drupal_get_path('module', 'views_bulk_operations') . '/css/modify.action.css';
|
137 |
|
|
$form['#tree'] = TRUE;
|
138 |
|
|
|
139 |
|
|
if (!empty($properties)) {
|
140 |
|
|
$form['properties'] = array(
|
141 |
|
|
'#type' => 'fieldset',
|
142 |
9df8b457
|
Assos Assos
|
'#title' => t('Properties'),
|
143 |
85ad3d82
|
Assos Assos
|
);
|
144 |
|
|
$form['properties']['show_value'] = array(
|
145 |
|
|
'#suffix' => '<div class="clearfix"></div>',
|
146 |
|
|
);
|
147 |
|
|
|
148 |
|
|
foreach ($properties as $key => $property) {
|
149 |
|
|
$form['properties']['show_value'][$key] = array(
|
150 |
|
|
'#type' => 'checkbox',
|
151 |
|
|
'#title' => $property['label'],
|
152 |
|
|
);
|
153 |
|
|
|
154 |
|
|
$determined_type = ($property['type'] == 'boolean') ? 'checkbox' : 'textfield';
|
155 |
|
|
$form['properties'][$key] = array(
|
156 |
|
|
'#type' => $determined_type,
|
157 |
|
|
'#title' => $property['label'],
|
158 |
|
|
'#description' => $property['description'],
|
159 |
|
|
'#states' => array(
|
160 |
|
|
'visible' => array(
|
161 |
|
|
'#edit-properties-show-value-' . str_replace('_', '-', $key) => array('checked' => TRUE),
|
162 |
|
|
),
|
163 |
|
|
),
|
164 |
|
|
);
|
165 |
|
|
// The default #maxlength for textfields is 128, while most varchar
|
166 |
|
|
// columns hold 255 characters, which makes it a saner default here.
|
167 |
|
|
if ($determined_type == 'textfield') {
|
168 |
|
|
$form['properties'][$key]['#maxlength'] = 255;
|
169 |
|
|
}
|
170 |
|
|
|
171 |
|
|
if (!empty($property['options list'])) {
|
172 |
|
|
$form['properties'][$key]['#type'] = 'select';
|
173 |
|
|
$form['properties'][$key]['#options'] = $property['options list']($key, array());
|
174 |
|
|
|
175 |
|
|
if ($property['type'] == 'list') {
|
176 |
|
|
$form['properties'][$key]['#type'] = 'checkboxes';
|
177 |
|
|
|
178 |
|
|
$form['properties']['_append::' . $key] = array(
|
179 |
|
|
'#type' => 'checkbox',
|
180 |
|
|
'#title' => t('Add new value(s) to %label, instead of overwriting the existing values.', array('%label' => $property['label'])),
|
181 |
|
|
'#states' => array(
|
182 |
|
|
'visible' => array(
|
183 |
|
|
'#edit-properties-show-value-' . $key => array('checked' => TRUE),
|
184 |
|
|
),
|
185 |
|
|
),
|
186 |
|
|
);
|
187 |
|
|
}
|
188 |
|
|
}
|
189 |
|
|
}
|
190 |
|
|
}
|
191 |
|
|
|
192 |
|
|
// Going to need this for multilingual nodes
|
193 |
|
|
global $language;
|
194 |
|
|
foreach ($bundles as $bundle_name => $bundle) {
|
195 |
|
|
$bundle_key = $info['entity keys']['bundle'];
|
196 |
|
|
$default_values = array();
|
197 |
|
|
// If the bundle key exists, it must always be set on an entity.
|
198 |
|
|
if (!empty($bundle_key)) {
|
199 |
|
|
$default_values[$bundle_key] = $bundle_name;
|
200 |
|
|
}
|
201 |
|
|
$default_values['language'] = $language->language;
|
202 |
|
|
$entity = entity_create($context['entity_type'], $default_values);
|
203 |
|
|
$form_state['entities'][$bundle_name] = $entity;
|
204 |
|
|
|
205 |
|
|
// Show the more detailed label only if the entity type has multiple bundles.
|
206 |
|
|
// Otherwise, it would just be confusing.
|
207 |
|
|
if (count($info['bundles']) > 1) {
|
208 |
|
|
$label = t('Fields for @bundle_key @label', array('@bundle_key' => $bundle_key, '@label' => $bundle['label']));
|
209 |
|
|
}
|
210 |
|
|
else {
|
211 |
|
|
$label = t('Fields');
|
212 |
|
|
}
|
213 |
|
|
|
214 |
|
|
$form_key = 'bundle_' . $bundle_name;
|
215 |
|
|
$form[$form_key] = array(
|
216 |
|
|
'#type' => 'fieldset',
|
217 |
|
|
'#title' => $label,
|
218 |
|
|
'#parents' => array($form_key),
|
219 |
|
|
);
|
220 |
|
|
field_attach_form($context['entity_type'], $entity, $form[$form_key], $form_state, entity_language($context['entity_type'], $entity));
|
221 |
|
|
// Now that all the widgets have been added, sort them by #weight.
|
222 |
|
|
// This ensures that they will stay in the correct order when they get
|
223 |
|
|
// assigned new weights.
|
224 |
|
|
uasort($form[$form_key], 'element_sort');
|
225 |
|
|
|
226 |
|
|
$display_values = $context['settings']['display_values'];
|
227 |
|
|
$instances = field_info_instances($entity_type, $bundle_name);
|
228 |
|
|
$weight = 0;
|
229 |
|
|
foreach (element_get_visible_children($form[$form_key]) as $field_name) {
|
230 |
|
|
// For our use case it makes no sense for any field widget to be required.
|
231 |
|
|
if (isset($form[$form_key][$field_name]['#language'])) {
|
232 |
|
|
$field_language = $form[$form_key][$field_name]['#language'];
|
233 |
|
|
_views_bulk_operations_modify_action_unset_required($form[$form_key][$field_name][$field_language]);
|
234 |
|
|
}
|
235 |
|
|
|
236 |
|
|
// The admin has specified which fields to display, but this field didn't
|
237 |
|
|
// make the cut. Hide it with #access => FALSE and move on.
|
238 |
|
|
if (empty($display_values[VBO_MODIFY_ACTION_ALL]) && empty($display_values[$bundle_name . '::' . $field_name])) {
|
239 |
|
|
$form[$form_key][$field_name]['#access'] = FALSE;
|
240 |
|
|
continue;
|
241 |
|
|
}
|
242 |
|
|
|
243 |
|
|
if (isset($instances[$field_name])) {
|
244 |
|
|
$field = $instances[$field_name];
|
245 |
|
|
$form[$form_key]['show_value'][$field_name] = array(
|
246 |
|
|
'#type' => 'checkbox',
|
247 |
|
|
'#title' => $field['label'],
|
248 |
|
|
);
|
249 |
|
|
$form[$form_key][$field_name]['#states'] = array(
|
250 |
|
|
'visible' => array(
|
251 |
|
|
'#edit-bundle-' . str_replace('_', '-', $bundle_name) . '-show-value-' . str_replace('_', '-', $field_name) => array('checked' => TRUE),
|
252 |
|
|
),
|
253 |
|
|
);
|
254 |
|
|
// All field widgets get reassigned weights so that additional elements
|
255 |
|
|
// added between them (such as "_append") can be properly ordered.
|
256 |
|
|
$form[$form_key][$field_name]['#weight'] = $weight++;
|
257 |
|
|
|
258 |
|
|
$field_info = field_info_field($field_name);
|
259 |
|
|
if ($field_info['cardinality'] != 1) {
|
260 |
|
|
$form[$form_key]['_append::' . $field_name] = array(
|
261 |
|
|
'#type' => 'checkbox',
|
262 |
|
|
'#title' => t('Add new value(s) to %label, instead of overwriting the existing values.', array('%label' => $field['label'])),
|
263 |
|
|
'#states' => array(
|
264 |
|
|
'visible' => array(
|
265 |
|
|
'#edit-bundle-' . str_replace('_', '-', $bundle_name) . '-show-value-' . str_replace('_', '-', $field_name) => array('checked' => TRUE),
|
266 |
|
|
),
|
267 |
|
|
),
|
268 |
|
|
'#weight' => $weight++,
|
269 |
|
|
);
|
270 |
|
|
}
|
271 |
|
|
}
|
272 |
|
|
}
|
273 |
|
|
|
274 |
|
|
// Add a clearfix below the checkboxes so that the widgets are not floated.
|
275 |
|
|
$form[$form_key]['show_value']['#suffix'] = '<div class="clearfix"></div>';
|
276 |
|
|
$form[$form_key]['show_value']['#weight'] = -1;
|
277 |
|
|
}
|
278 |
|
|
|
279 |
|
|
// If the form has only one group (for example, "Properties"), remove the
|
280 |
|
|
// title and the fieldset, since there's no need to visually group values.
|
281 |
|
|
$form_elements = element_get_visible_children($form);
|
282 |
|
|
if (count($form_elements) == 1) {
|
283 |
|
|
$element_key = reset($form_elements);
|
284 |
|
|
unset($form[$element_key]['#type']);
|
285 |
|
|
unset($form[$element_key]['#title']);
|
286 |
|
|
|
287 |
|
|
// Get a list of all elements in the group, and filter out the non-values.
|
288 |
|
|
$values = element_get_visible_children($form[$element_key]);
|
289 |
|
|
foreach ($values as $index => $key) {
|
290 |
|
|
if ($key == 'show_value' || substr($key, 0, 1) == '_') {
|
291 |
|
|
unset($values[$index]);
|
292 |
|
|
}
|
293 |
|
|
}
|
294 |
|
|
// If the group has only one value, no need to hide it through #states.
|
295 |
|
|
if (count($values) == 1) {
|
296 |
|
|
$value_key = reset($values);
|
297 |
|
|
$form[$element_key]['show_value'][$value_key]['#type'] = 'value';
|
298 |
|
|
$form[$element_key]['show_value'][$value_key]['#value'] = TRUE;
|
299 |
|
|
}
|
300 |
|
|
}
|
301 |
|
|
|
302 |
|
|
if (module_exists('token') && $context['settings']['show_all_tokens']) {
|
303 |
|
|
$token_type = str_replace('_', '-', $entity_type);
|
304 |
|
|
$form['tokens'] = array(
|
305 |
|
|
'#type' => 'fieldset',
|
306 |
9df8b457
|
Assos Assos
|
'#title' => t('Available tokens'),
|
307 |
85ad3d82
|
Assos Assos
|
'#collapsible' => TRUE,
|
308 |
|
|
'#collapsed' => TRUE,
|
309 |
|
|
'#weight' => 998,
|
310 |
|
|
);
|
311 |
|
|
$form['tokens']['tree'] = array(
|
312 |
|
|
'#theme' => 'token_tree',
|
313 |
|
|
'#token_types' => array($token_type, 'site'),
|
314 |
|
|
'#global_types' => array(),
|
315 |
|
|
'#dialog' => TRUE,
|
316 |
|
|
);
|
317 |
|
|
}
|
318 |
|
|
|
319 |
|
|
return $form;
|
320 |
|
|
}
|
321 |
|
|
|
322 |
|
|
/**
|
323 |
|
|
* Action form validate function.
|
324 |
|
|
*
|
325 |
|
|
* Checks that the user selected at least one value to modify, validates
|
326 |
|
|
* properties and calls Field API to validate fields for each bundle.
|
327 |
|
|
*/
|
328 |
|
|
function views_bulk_operations_modify_action_validate($form, &$form_state) {
|
329 |
|
|
// The form structure for "Show" checkboxes is a bit bumpy.
|
330 |
|
|
$search = array('properties');
|
331 |
|
|
foreach ($form_state['entities'] as $bundle => $entity) {
|
332 |
|
|
$search[] = 'bundle_' . $bundle;
|
333 |
|
|
}
|
334 |
|
|
|
335 |
|
|
$has_selected = FALSE;
|
336 |
|
|
foreach ($search as $group) {
|
337 |
|
|
// Store names of selected and appended entity values in a nicer format.
|
338 |
|
|
$form_state['selected'][$group] = array();
|
339 |
|
|
$form_state['append'][$group] = array();
|
340 |
|
|
|
341 |
|
|
// This group has no values, move on.
|
342 |
|
|
if (!isset($form_state['values'][$group])) {
|
343 |
|
|
continue;
|
344 |
|
|
}
|
345 |
|
|
|
346 |
|
|
foreach ($form_state['values'][$group]['show_value'] as $key => $value) {
|
347 |
|
|
if ($value) {
|
348 |
|
|
$has_selected = TRUE;
|
349 |
|
|
$form_state['selected'][$group][] = $key;
|
350 |
|
|
}
|
351 |
|
|
if (!empty($form_state['values'][$group]['_append::' . $key])) {
|
352 |
|
|
$form_state['append'][$group][] = $key;
|
353 |
|
|
unset($form_state['values'][$group]['_append::' . $key]);
|
354 |
|
|
}
|
355 |
|
|
}
|
356 |
|
|
unset($form_state['values'][$group]['show_value']);
|
357 |
|
|
}
|
358 |
|
|
|
359 |
|
|
if (!$has_selected) {
|
360 |
|
|
form_set_error('', t('You must select at least one value to modify.'));
|
361 |
|
|
return;
|
362 |
|
|
}
|
363 |
|
|
|
364 |
|
|
// Use the wrapper to validate property values.
|
365 |
|
|
if (!empty($form_state['selected']['properties'])) {
|
366 |
|
|
// The entity used is irrelevant, and we can't rely on
|
367 |
|
|
// $form_state['entities'] being non-empty, so a new one is created.
|
368 |
|
|
$info = entity_get_info($form_state['entity_type']);
|
369 |
|
|
$bundle_key = $info['entity keys']['bundle'];
|
370 |
|
|
$default_values = array();
|
371 |
|
|
// If the bundle key exists, it must always be set on an entity.
|
372 |
|
|
if (!empty($bundle_key)) {
|
373 |
|
|
$bundle_names = array_keys($info['bundles']);
|
374 |
|
|
$bundle_name = reset($bundle_names);
|
375 |
|
|
$default_values[$bundle_key] = $bundle_name;
|
376 |
|
|
}
|
377 |
|
|
$entity = entity_create($form_state['entity_type'], $default_values);
|
378 |
|
|
$wrapper = entity_metadata_wrapper($form_state['entity_type'], $entity);
|
379 |
|
|
|
380 |
|
|
$properties = _views_bulk_operations_modify_action_get_properties($form_state['entity_type']);
|
381 |
|
|
foreach ($form_state['selected']['properties'] as $key) {
|
382 |
|
|
$value = $form_state['values']['properties'][$key];
|
383 |
|
|
if (!$wrapper->$key->validate($value)) {
|
384 |
|
|
$label = $properties[$key]['label'];
|
385 |
|
|
form_set_error('properties][' . $key, t('%label contains an invalid value.', array('%label' => $label)));
|
386 |
|
|
}
|
387 |
|
|
}
|
388 |
|
|
}
|
389 |
|
|
|
390 |
|
|
foreach ($form_state['entities'] as $bundle_name => $entity) {
|
391 |
|
|
field_attach_form_validate($form_state['entity_type'], $entity, $form['bundle_' . $bundle_name], $form_state);
|
392 |
|
|
}
|
393 |
|
|
}
|
394 |
|
|
|
395 |
|
|
/**
|
396 |
|
|
* Action form submit function.
|
397 |
|
|
*
|
398 |
|
|
* Fills each constructed entity with property and field values, then
|
399 |
|
|
* passes them to views_bulk_operations_modify_action().
|
400 |
|
|
*/
|
401 |
|
|
function views_bulk_operations_modify_action_submit($form, $form_state) {
|
402 |
|
|
foreach ($form_state['entities'] as $bundle_name => $entity) {
|
403 |
|
|
field_attach_submit($form_state['entity_type'], $entity, $form['bundle_' . $bundle_name], $form_state);
|
404 |
|
|
}
|
405 |
|
|
|
406 |
|
|
return array(
|
407 |
|
|
'append' => $form_state['append'],
|
408 |
|
|
'selected' => $form_state['selected'],
|
409 |
|
|
'entities' => $form_state['entities'],
|
410 |
|
|
'properties' => isset($form_state['values']['properties']) ? $form_state['values']['properties'] : array(),
|
411 |
|
|
);
|
412 |
|
|
}
|
413 |
|
|
|
414 |
|
|
/**
|
415 |
|
|
* Returns all properties that can be modified.
|
416 |
|
|
*
|
417 |
|
|
* Properties that can't be changed are entity keys, timestamps, and the ones
|
418 |
|
|
* without a setter callback.
|
419 |
|
|
*
|
420 |
|
|
* @param $entity_type
|
421 |
|
|
* The entity type whose properties will be fetched.
|
422 |
|
|
* @param $display_values
|
423 |
|
|
* An optional, admin-provided list of properties and fields that should be
|
424 |
|
|
* displayed for editing, used to filter the returned list of properties.
|
425 |
|
|
*/
|
426 |
|
|
function _views_bulk_operations_modify_action_get_properties($entity_type, $display_values = NULL) {
|
427 |
|
|
$properties = array();
|
428 |
|
|
$info = entity_get_info($entity_type);
|
429 |
|
|
|
430 |
|
|
// List of properties that can't be modified.
|
431 |
|
|
$disabled_properties = array('created', 'changed');
|
432 |
|
|
foreach (array('id', 'bundle', 'revision') as $key) {
|
433 |
|
|
if (!empty($info['entity keys'][$key])) {
|
434 |
|
|
$disabled_properties[] = $info['entity keys'][$key];
|
435 |
|
|
}
|
436 |
|
|
}
|
437 |
|
|
// List of supported types.
|
438 |
|
|
$supported_types = array('text', 'token', 'integer', 'decimal', 'date', 'duration',
|
439 |
|
|
'boolean', 'uri', 'list');
|
440 |
|
|
$property_info = entity_get_property_info($entity_type);
|
441 |
|
|
if (empty($property_info['properties'])) {
|
442 |
|
|
// Stop here if no properties were found.
|
443 |
|
|
return array();
|
444 |
|
|
}
|
445 |
|
|
|
446 |
|
|
foreach ($property_info['properties'] as $key => $property) {
|
447 |
|
|
if (in_array($key, $disabled_properties)) {
|
448 |
|
|
continue;
|
449 |
|
|
}
|
450 |
|
|
// Filter out properties that can't be set (they are usually generated by a
|
451 |
|
|
// getter callback based on other properties, and not stored in the DB).
|
452 |
|
|
if (empty($property['setter callback'])) {
|
453 |
|
|
continue;
|
454 |
|
|
}
|
455 |
|
|
// Determine the property type. If it's empty (permitted), default to text.
|
456 |
|
|
// If it's a list type such as list<boolean>, extract the "boolean" part.
|
457 |
|
|
$property['type'] = empty($property['type']) ? 'text' : $property['type'];
|
458 |
|
|
$type = $property['type'];
|
459 |
|
|
if ($list_type = entity_property_list_extract_type($type)) {
|
460 |
|
|
$type = $list_type;
|
461 |
|
|
$property['type'] = 'list';
|
462 |
|
|
}
|
463 |
|
|
// Filter out non-supported types (such as the Field API fields that
|
464 |
|
|
// Commerce adds to its entities so that they show up in tokens).
|
465 |
|
|
if (!in_array($type, $supported_types)) {
|
466 |
|
|
continue;
|
467 |
|
|
}
|
468 |
|
|
|
469 |
|
|
$properties[$key] = $property;
|
470 |
|
|
}
|
471 |
|
|
|
472 |
|
|
if (isset($display_values) && empty($display_values[VBO_MODIFY_ACTION_ALL])) {
|
473 |
|
|
// Return only the properties that the admin specified.
|
474 |
|
|
return array_intersect_key($properties, $display_values);
|
475 |
|
|
}
|
476 |
|
|
|
477 |
|
|
return $properties;
|
478 |
|
|
}
|
479 |
|
|
|
480 |
|
|
/**
|
481 |
|
|
* Returns all bundles for which field widgets should be displayed.
|
482 |
|
|
*
|
483 |
|
|
* If the admin decided to limit the modify form to certain properties / fields
|
484 |
|
|
* (through the action settings) then only bundles that have at least one field
|
485 |
|
|
* selected are returned.
|
486 |
|
|
*
|
487 |
|
|
* @param $entity_type
|
488 |
|
|
* The entity type whose bundles will be fetched.
|
489 |
|
|
* @param $context
|
490 |
|
|
* The VBO context variable.
|
491 |
|
|
*/
|
492 |
|
|
function _views_bulk_operations_modify_action_get_bundles($entity_type, $context) {
|
493 |
|
|
$bundles = array();
|
494 |
|
|
|
495 |
|
|
$view = $context['view'];
|
496 |
|
|
$vbo = _views_bulk_operations_get_field($view);
|
497 |
|
|
$display_values = $context['settings']['display_values'];
|
498 |
|
|
$info = entity_get_info($entity_type);
|
499 |
|
|
$bundle_key = $info['entity keys']['bundle'];
|
500 |
|
|
|
501 |
|
|
// Check if this View has a filter on the bundle key and assemble a list
|
502 |
|
|
// of allowed bundles according to the filter.
|
503 |
|
|
$filtered_bundles = array_keys($info['bundles']);
|
504 |
|
|
|
505 |
|
|
// Go over all the filters and find any relevant ones.
|
506 |
|
|
foreach ($view->filter as $key => $filter) {
|
507 |
|
|
// Check it's the right field on the right table.
|
508 |
|
|
if ($filter->table == $vbo->table && $filter->field == $bundle_key) {
|
509 |
|
|
// Exposed filters may have no bundles, so check that there is a value.
|
510 |
|
|
if (empty($filter->value)) {
|
511 |
|
|
continue;
|
512 |
|
|
}
|
513 |
|
|
|
514 |
|
|
$operator = $filter->operator;
|
515 |
|
|
if ($operator == 'in') {
|
516 |
|
|
$filtered_bundles = array_intersect($filtered_bundles, $filter->value);
|
517 |
|
|
}
|
518 |
|
|
elseif ($operator == 'not in') {
|
519 |
|
|
$filtered_bundles = array_diff($filtered_bundles, $filter->value);
|
520 |
|
|
}
|
521 |
|
|
}
|
522 |
|
|
}
|
523 |
|
|
|
524 |
|
|
foreach ($info['bundles'] as $bundle_name => $bundle) {
|
525 |
|
|
// The view is limited to specific bundles, but this bundle isn't one of
|
526 |
|
|
// them. Ignore it.
|
527 |
|
|
if (!in_array($bundle_name, $filtered_bundles)) {
|
528 |
|
|
continue;
|
529 |
|
|
}
|
530 |
|
|
|
531 |
|
|
$instances = field_info_instances($entity_type, $bundle_name);
|
532 |
|
|
// Ignore bundles that don't have any field instances attached.
|
533 |
|
|
if (empty($instances)) {
|
534 |
|
|
continue;
|
535 |
|
|
}
|
536 |
|
|
|
537 |
|
|
$has_enabled_fields = FALSE;
|
538 |
|
|
foreach ($display_values as $key) {
|
539 |
|
|
if (strpos($key, $bundle_name . '::') !== FALSE) {
|
540 |
|
|
$has_enabled_fields = TRUE;
|
541 |
|
|
}
|
542 |
|
|
}
|
543 |
|
|
// The admin has either specified that all values should be modifiable, or
|
544 |
|
|
// selected at least one field belonging to this bundle.
|
545 |
|
|
if (!empty($display_values[VBO_MODIFY_ACTION_ALL]) || $has_enabled_fields) {
|
546 |
|
|
$bundles[$bundle_name] = $bundle;
|
547 |
|
|
}
|
548 |
|
|
}
|
549 |
|
|
|
550 |
|
|
return $bundles;
|
551 |
|
|
}
|
552 |
|
|
|
553 |
|
|
/**
|
554 |
|
|
* Helper function that recursively strips #required from field widgets.
|
555 |
|
|
*/
|
556 |
|
|
function _views_bulk_operations_modify_action_unset_required(&$element) {
|
557 |
|
|
unset($element['#required']);
|
558 |
|
|
foreach (element_children($element) as $key) {
|
559 |
|
|
_views_bulk_operations_modify_action_unset_required($element[$key]);
|
560 |
|
|
}
|
561 |
|
|
}
|
562 |
|
|
|
563 |
|
|
/**
|
564 |
|
|
* VBO settings form function.
|
565 |
|
|
*/
|
566 |
|
|
function views_bulk_operations_modify_action_views_bulk_operations_form_options() {
|
567 |
|
|
$options['show_all_tokens'] = TRUE;
|
568 |
|
|
$options['display_values'] = array(VBO_MODIFY_ACTION_ALL);
|
569 |
|
|
return $options;
|
570 |
|
|
}
|
571 |
|
|
|
572 |
|
|
/**
|
573 |
|
|
* The settings form for this action.
|
574 |
|
|
*/
|
575 |
|
|
function views_bulk_operations_modify_action_views_bulk_operations_form($options, $entity_type, $dom_id) {
|
576 |
|
|
// Initialize default values.
|
577 |
|
|
if (empty($options)) {
|
578 |
|
|
$options = views_bulk_operations_modify_action_views_bulk_operations_form_options();
|
579 |
|
|
}
|
580 |
|
|
|
581 |
|
|
$form['show_all_tokens'] = array(
|
582 |
|
|
'#type' => 'checkbox',
|
583 |
|
|
'#title' => t('Show available tokens'),
|
584 |
|
|
'#description' => t('Check this to show a list of all available tokens in the bottom of the form. Requires the token module.'),
|
585 |
|
|
'#default_value' => $options['show_all_tokens'],
|
586 |
|
|
);
|
587 |
|
|
|
588 |
|
|
$info = entity_get_info($entity_type);
|
589 |
|
|
$properties = _views_bulk_operations_modify_action_get_properties($entity_type);
|
590 |
|
|
$values = array(VBO_MODIFY_ACTION_ALL => t('- All -'));
|
591 |
|
|
foreach ($properties as $key => $property) {
|
592 |
|
|
$label = t('Properties');
|
593 |
|
|
$values[$label][$key] = $property['label'];
|
594 |
|
|
}
|
595 |
|
|
foreach ($info['bundles'] as $bundle_name => $bundle) {
|
596 |
|
|
$bundle_key = $info['entity keys']['bundle'];
|
597 |
|
|
// Show the more detailed label only if the entity type has multiple bundles.
|
598 |
|
|
// Otherwise, it would just be confusing.
|
599 |
|
|
if (count($info['bundles']) > 1) {
|
600 |
|
|
$label = t('Fields for @bundle_key @label', array('@bundle_key' => $bundle_key, '@label' => $bundle['label']));
|
601 |
|
|
}
|
602 |
|
|
else {
|
603 |
|
|
$label = t('Fields');
|
604 |
|
|
}
|
605 |
|
|
|
606 |
|
|
$instances = field_info_instances($entity_type, $bundle_name);
|
607 |
|
|
foreach ($instances as $field_name => $field) {
|
608 |
|
|
$values[$label][$bundle_name . '::' . $field_name] = $field['label'];
|
609 |
|
|
}
|
610 |
|
|
}
|
611 |
|
|
|
612 |
|
|
$form['display_values'] = array(
|
613 |
|
|
'#type' => 'select',
|
614 |
|
|
'#title' => t('Display values'),
|
615 |
|
|
'#options' => $values,
|
616 |
|
|
'#multiple' => TRUE,
|
617 |
|
|
'#description' => t('Select which values the action form should present to the user.'),
|
618 |
|
|
'#default_value' => $options['display_values'],
|
619 |
|
|
'#size' => 10,
|
620 |
|
|
);
|
621 |
|
|
return $form;
|
622 |
|
|
} |