danielebarchiesi@4
|
1 <?php
|
danielebarchiesi@4
|
2
|
danielebarchiesi@4
|
3 /**
|
danielebarchiesi@4
|
4 * @file
|
danielebarchiesi@4
|
5 * Defines a field type for referencing one node from another.
|
danielebarchiesi@4
|
6 */
|
danielebarchiesi@4
|
7
|
danielebarchiesi@4
|
8 /**
|
danielebarchiesi@4
|
9 * Implements hook_menu().
|
danielebarchiesi@4
|
10 */
|
danielebarchiesi@4
|
11 function node_reference_menu() {
|
danielebarchiesi@4
|
12 $items['node_reference/autocomplete/%/%/%'] = array(
|
danielebarchiesi@4
|
13 'page callback' => 'node_reference_autocomplete',
|
danielebarchiesi@4
|
14 'page arguments' => array(2, 3, 4),
|
danielebarchiesi@4
|
15 'access callback' => 'reference_autocomplete_access',
|
danielebarchiesi@4
|
16 'access arguments' => array(2, 3, 4),
|
danielebarchiesi@4
|
17 'type' => MENU_CALLBACK,
|
danielebarchiesi@4
|
18 );
|
danielebarchiesi@4
|
19 return $items;
|
danielebarchiesi@4
|
20 }
|
danielebarchiesi@4
|
21
|
danielebarchiesi@4
|
22 /**
|
danielebarchiesi@4
|
23 * Implements hook_field_info().
|
danielebarchiesi@4
|
24 */
|
danielebarchiesi@4
|
25 function node_reference_field_info() {
|
danielebarchiesi@4
|
26 return array(
|
danielebarchiesi@4
|
27 'node_reference' => array(
|
danielebarchiesi@4
|
28 'label' => t('Node reference'),
|
danielebarchiesi@4
|
29 'description' => t('This field stores the ID of a related node as an integer value.'),
|
danielebarchiesi@4
|
30 'settings' => array(
|
danielebarchiesi@4
|
31 'referenceable_types' => array(),
|
danielebarchiesi@4
|
32 'view' => array(
|
danielebarchiesi@4
|
33 'view_name' => '',
|
danielebarchiesi@4
|
34 'display_name' => '',
|
danielebarchiesi@4
|
35 'args' => array(),
|
danielebarchiesi@4
|
36 ),
|
danielebarchiesi@4
|
37 ),
|
danielebarchiesi@4
|
38 // It probably make more sense to have the referenceable types be per-field than per-instance
|
danielebarchiesi@4
|
39 // 'instance settings' => array('referenceable_types' => array()),
|
danielebarchiesi@4
|
40 'default_widget' => 'options_select', // node_reference_autocomplete',
|
danielebarchiesi@4
|
41 'default_formatter' => 'node_reference_default',
|
danielebarchiesi@4
|
42 // Support hook_entity_property_info() from contrib "Entity API".
|
danielebarchiesi@4
|
43 'property_type' => 'node',
|
danielebarchiesi@4
|
44 // Support default token formatter for field tokens.
|
danielebarchiesi@4
|
45 'default_token_formatter' => 'node_reference_plain',
|
danielebarchiesi@4
|
46 ),
|
danielebarchiesi@4
|
47 );
|
danielebarchiesi@4
|
48 }
|
danielebarchiesi@4
|
49
|
danielebarchiesi@4
|
50 /**
|
danielebarchiesi@4
|
51 * Implements hook_field_settings_form().
|
danielebarchiesi@4
|
52 */
|
danielebarchiesi@4
|
53 function node_reference_field_settings_form($field, $instance, $has_data) {
|
danielebarchiesi@4
|
54 $settings = $field['settings'];
|
danielebarchiesi@4
|
55
|
danielebarchiesi@4
|
56 $form = array();
|
danielebarchiesi@4
|
57 $form['referenceable_types'] = array(
|
danielebarchiesi@4
|
58 '#type' => 'checkboxes',
|
danielebarchiesi@4
|
59 '#title' => t('Content types that can be referenced'),
|
danielebarchiesi@4
|
60 '#multiple' => TRUE,
|
danielebarchiesi@4
|
61 '#default_value' => $settings['referenceable_types'],
|
danielebarchiesi@4
|
62 '#options' => array_map('check_plain', node_type_get_names()),
|
danielebarchiesi@4
|
63 );
|
danielebarchiesi@4
|
64
|
danielebarchiesi@4
|
65 if (module_exists('views')) {
|
danielebarchiesi@4
|
66 $view_settings = $settings['view'];
|
danielebarchiesi@4
|
67
|
danielebarchiesi@4
|
68 $description = '<p>' . t('The list of nodes that can be referenced can provided by a view (Views module) using the "References" display type.') . '</p>';
|
danielebarchiesi@4
|
69
|
danielebarchiesi@4
|
70 // Special note for legacy fields migrated from D6.
|
danielebarchiesi@4
|
71 if (!empty($view_settings['view_name']) && $view_settings['display_name'] == 'default') {
|
danielebarchiesi@4
|
72 $description .= '<p><strong><span class="admin-missing">'. t("Important D6 migration note:") . '</span></strong>';
|
danielebarchiesi@4
|
73 $description .= '<br/>' . t("The field is currently configured to use the 'Master' display of the view %view_name.", array('%view_name' => $view_settings['view_name']));
|
danielebarchiesi@4
|
74 $description .= '<br/>' . t("It is highly recommended that you: <br/>- edit this view and create a new display using the 'References' display type, <br/>- update the field settings to explicitly select the correct view and display.");
|
danielebarchiesi@4
|
75 $description .= '<br/>' . t("The field will work correctly until then, but submitting this form might inadvertently change the field settings.") . '</p>';
|
danielebarchiesi@4
|
76 }
|
danielebarchiesi@4
|
77
|
danielebarchiesi@4
|
78 $form['view'] = array(
|
danielebarchiesi@4
|
79 '#type' => 'fieldset',
|
danielebarchiesi@4
|
80 '#title' => t('Views - Nodes that can be referenced'),
|
danielebarchiesi@4
|
81 '#collapsible' => TRUE,
|
danielebarchiesi@4
|
82 '#collapsed' => empty($view_settings['view_name']),
|
danielebarchiesi@4
|
83 '#description' => $description,
|
danielebarchiesi@4
|
84 );
|
danielebarchiesi@4
|
85
|
danielebarchiesi@4
|
86 $views_options = references_get_views_options('node');
|
danielebarchiesi@4
|
87 if ($views_options) {
|
danielebarchiesi@4
|
88 // The value of the 'view_and_display' select below will need to be split
|
danielebarchiesi@4
|
89 // into 'view_name' and 'view_display' in the final submitted values, so
|
danielebarchiesi@4
|
90 // we massage the data at validate time on the wrapping element (not
|
danielebarchiesi@4
|
91 // ideal).
|
danielebarchiesi@4
|
92 $form['view']['#element_validate'] = array('_node_reference_view_settings_validate');
|
danielebarchiesi@4
|
93
|
danielebarchiesi@4
|
94 $views_options = array('' => '<' . t('none') . '>') + $views_options;
|
danielebarchiesi@4
|
95 $default = empty($view_settings['view_name']) ? '' : $view_settings['view_name'] . ':' .$view_settings['display_name'];
|
danielebarchiesi@4
|
96 $form['view']['view_and_display'] = array(
|
danielebarchiesi@4
|
97 '#type' => 'select',
|
danielebarchiesi@4
|
98 '#title' => t('View used to select the nodes'),
|
danielebarchiesi@4
|
99 '#options' => $views_options,
|
danielebarchiesi@4
|
100 '#default_value' => $default,
|
danielebarchiesi@4
|
101 '#description' => '<p>' . t('Choose the view and display that select the nodes that can be referenced.<br />Only views with a display of type "References" are eligible.') . '</p>' .
|
danielebarchiesi@4
|
102 t('Note:<ul><li>This will discard the "Content types" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate nodes on node creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate nodes will be displayed.</li></ul>'),
|
danielebarchiesi@4
|
103 );
|
danielebarchiesi@4
|
104
|
danielebarchiesi@4
|
105 $default = implode(', ', $view_settings['args']);
|
danielebarchiesi@4
|
106 $form['view']['args'] = array(
|
danielebarchiesi@4
|
107 '#type' => 'textfield',
|
danielebarchiesi@4
|
108 '#title' => t('View arguments'),
|
danielebarchiesi@4
|
109 '#default_value' => $default,
|
danielebarchiesi@4
|
110 '#required' => FALSE,
|
danielebarchiesi@4
|
111 '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
|
danielebarchiesi@4
|
112 );
|
danielebarchiesi@4
|
113 }
|
danielebarchiesi@4
|
114 else {
|
danielebarchiesi@4
|
115 $form['view']['no_view_help'] = array(
|
danielebarchiesi@4
|
116 '#markup' => '<p>' . t('No eligible view was found.') .'</p>',
|
danielebarchiesi@4
|
117 );
|
danielebarchiesi@4
|
118 }
|
danielebarchiesi@4
|
119 }
|
danielebarchiesi@4
|
120
|
danielebarchiesi@4
|
121 return $form;
|
danielebarchiesi@4
|
122 }
|
danielebarchiesi@4
|
123
|
danielebarchiesi@4
|
124 /**
|
danielebarchiesi@4
|
125 * Validate callback for the 'view settings' fieldset.
|
danielebarchiesi@4
|
126 *
|
danielebarchiesi@4
|
127 * Puts back the various form values in the expected shape.
|
danielebarchiesi@4
|
128 */
|
danielebarchiesi@4
|
129 function _node_reference_view_settings_validate($element, &$form_state, $form) {
|
danielebarchiesi@4
|
130 // Split view name and display name from the 'view_and_display' value.
|
danielebarchiesi@4
|
131 if (!empty($element['view_and_display']['#value'])) {
|
danielebarchiesi@4
|
132 list($view, $display) = explode(':', $element['view_and_display']['#value']);
|
danielebarchiesi@4
|
133 }
|
danielebarchiesi@4
|
134 else {
|
danielebarchiesi@4
|
135 $view = '';
|
danielebarchiesi@4
|
136 $display = '';
|
danielebarchiesi@4
|
137 }
|
danielebarchiesi@4
|
138
|
danielebarchiesi@4
|
139 // Explode the 'args' string into an actual array. Beware, explode() turns an
|
danielebarchiesi@4
|
140 // empty string into an array with one empty string. We'll need an empty array
|
danielebarchiesi@4
|
141 // instead.
|
danielebarchiesi@4
|
142 $args_string = trim($element['args']['#value']);
|
danielebarchiesi@4
|
143 $args = ($args_string === '') ? array() : array_map('trim', explode(',', $args_string));
|
danielebarchiesi@4
|
144
|
danielebarchiesi@4
|
145 $value = array('view_name' => $view, 'display_name' => $display, 'args' => $args);
|
danielebarchiesi@4
|
146 form_set_value($element, $value, $form_state);
|
danielebarchiesi@4
|
147 }
|
danielebarchiesi@4
|
148
|
danielebarchiesi@4
|
149 /**
|
danielebarchiesi@4
|
150 * Implements hook_field_validate().
|
danielebarchiesi@4
|
151 *
|
danielebarchiesi@4
|
152 * Possible error codes:
|
danielebarchiesi@4
|
153 * - 'invalid_nid': nid is not valid for the field (not a valid node id, or the node is not referenceable).
|
danielebarchiesi@4
|
154 */
|
danielebarchiesi@4
|
155 function node_reference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
|
danielebarchiesi@4
|
156 // Extract nids to check.
|
danielebarchiesi@4
|
157 $ids = array();
|
danielebarchiesi@4
|
158
|
danielebarchiesi@4
|
159 // First check non-numeric "nid's to avoid losing time with them.
|
danielebarchiesi@4
|
160 foreach ($items as $delta => $item) {
|
danielebarchiesi@4
|
161 if (is_array($item) && !empty($item['nid'])) {
|
danielebarchiesi@4
|
162 if (is_numeric($item['nid'])) {
|
danielebarchiesi@4
|
163 $ids[] = $item['nid'];
|
danielebarchiesi@4
|
164 }
|
danielebarchiesi@4
|
165 else {
|
danielebarchiesi@4
|
166 $errors[$field['field_name']][$langcode][$delta][] = array(
|
danielebarchiesi@4
|
167 'error' => 'invalid_nid',
|
danielebarchiesi@4
|
168 'message' => t("%name: invalid input.",
|
danielebarchiesi@4
|
169 array('%name' => $instance['label'])),
|
danielebarchiesi@4
|
170 );
|
danielebarchiesi@4
|
171 }
|
danielebarchiesi@4
|
172 }
|
danielebarchiesi@4
|
173 }
|
danielebarchiesi@4
|
174 // Prevent performance hog if there are no ids to check.
|
danielebarchiesi@4
|
175 if ($ids) {
|
danielebarchiesi@4
|
176 $options = array(
|
danielebarchiesi@4
|
177 'ids' => $ids,
|
danielebarchiesi@4
|
178 );
|
danielebarchiesi@4
|
179 $refs = node_reference_potential_references($field, $options);
|
danielebarchiesi@4
|
180 foreach ($items as $delta => $item) {
|
danielebarchiesi@4
|
181 if (is_array($item)) {
|
danielebarchiesi@4
|
182 if (!empty($item['nid']) && !isset($refs[$item['nid']])) {
|
danielebarchiesi@4
|
183 $errors[$field['field_name']][$langcode][$delta][] = array(
|
danielebarchiesi@4
|
184 'error' => 'invalid_nid',
|
danielebarchiesi@4
|
185 'message' => t("%name: this post can't be referenced.",
|
danielebarchiesi@4
|
186 array('%name' => $instance['label'])),
|
danielebarchiesi@4
|
187 );
|
danielebarchiesi@4
|
188 }
|
danielebarchiesi@4
|
189 }
|
danielebarchiesi@4
|
190 }
|
danielebarchiesi@4
|
191 }
|
danielebarchiesi@4
|
192 }
|
danielebarchiesi@4
|
193
|
danielebarchiesi@4
|
194 /**
|
danielebarchiesi@4
|
195 * Implements hook_field_prepare_view().
|
danielebarchiesi@4
|
196 */
|
danielebarchiesi@4
|
197 function node_reference_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
|
danielebarchiesi@4
|
198 $checked_ids = &drupal_static(__FUNCTION__, array());
|
danielebarchiesi@4
|
199
|
danielebarchiesi@4
|
200 // Set an 'access' property on each item (TRUE if the node exists and is
|
danielebarchiesi@4
|
201 // accessible by the current user).
|
danielebarchiesi@4
|
202
|
danielebarchiesi@4
|
203 // Extract ids to check.
|
danielebarchiesi@4
|
204 $ids = array();
|
danielebarchiesi@4
|
205 foreach ($items as $id => $entity_items) {
|
danielebarchiesi@4
|
206 foreach ($entity_items as $delta => $item) {
|
danielebarchiesi@4
|
207 if (is_array($item)) {
|
danielebarchiesi@4
|
208 // Default to 'not accessible'.
|
danielebarchiesi@4
|
209 $items[$id][$delta]['access'] = FALSE;
|
danielebarchiesi@4
|
210 if (!empty($item['nid']) && is_numeric($item['nid'])) {
|
danielebarchiesi@4
|
211 $ids[$item['nid']] = $item['nid'];
|
danielebarchiesi@4
|
212 }
|
danielebarchiesi@4
|
213 }
|
danielebarchiesi@4
|
214 }
|
danielebarchiesi@4
|
215 }
|
danielebarchiesi@4
|
216
|
danielebarchiesi@4
|
217 if ($ids) {
|
danielebarchiesi@4
|
218 // Load information about ids that we haven't already loaded during this
|
danielebarchiesi@4
|
219 // page request.
|
danielebarchiesi@4
|
220 $ids_to_check = array_diff($ids, array_keys($checked_ids));
|
danielebarchiesi@4
|
221 if (!empty($ids_to_check)) {
|
danielebarchiesi@4
|
222 $query = db_select('node', 'n')
|
danielebarchiesi@4
|
223 ->addTag('node_access')
|
danielebarchiesi@4
|
224 ->addMetaData('id', 'node_reference_field_prepare_view')
|
danielebarchiesi@4
|
225 ->addMetaData('field', $field)
|
danielebarchiesi@4
|
226 ->fields('n', array('nid'))
|
danielebarchiesi@4
|
227 // WHERE n.nid IN (nids to check) AND ...
|
danielebarchiesi@4
|
228 ->condition('n.nid', $ids_to_check, 'IN');
|
danielebarchiesi@4
|
229
|
danielebarchiesi@4
|
230 // Unless the user has the right permissions, restrict on the node status.
|
danielebarchiesi@4
|
231 // (note: the 'view any unpublished content' permission is provided by the
|
danielebarchiesi@4
|
232 // 'view_unpublished' contrib module.)
|
danielebarchiesi@4
|
233 if (!user_access('bypass node access') && !user_access('view any unpublished content')) {
|
danielebarchiesi@4
|
234 // ... AND n.status = 1
|
danielebarchiesi@4
|
235 $status_condition = db_or()
|
danielebarchiesi@4
|
236 ->condition('n.status', NODE_PUBLISHED);
|
danielebarchiesi@4
|
237
|
danielebarchiesi@4
|
238 // Take the 'view own unpublished content' permission into account to
|
danielebarchiesi@4
|
239 // decide whether some unpublished nodes should still be visible.
|
danielebarchiesi@4
|
240 if (user_access('view own unpublished content') && $own_unpublished = db_query('SELECT nid FROM {node} WHERE uid = :uid AND status = :status', array(':uid' => $GLOBALS['user']->uid, ':status' => NODE_NOT_PUBLISHED))->fetchCol()) {
|
danielebarchiesi@4
|
241 // ... AND (n.status = 1 OR n.nid IN (own unpublished))
|
danielebarchiesi@4
|
242 $status_condition
|
danielebarchiesi@4
|
243 ->condition('n.nid', $own_unpublished, 'IN');
|
danielebarchiesi@4
|
244 }
|
danielebarchiesi@4
|
245
|
danielebarchiesi@4
|
246 $query->condition($status_condition);
|
danielebarchiesi@4
|
247 }
|
danielebarchiesi@4
|
248
|
danielebarchiesi@4
|
249 $accessible_ids = $query->execute()->fetchAllAssoc('nid');
|
danielebarchiesi@4
|
250
|
danielebarchiesi@4
|
251 // Populate our static list so that we do not query on those ids again.
|
danielebarchiesi@4
|
252 foreach ($ids_to_check as $id) {
|
danielebarchiesi@4
|
253 $checked_ids[$id] = isset($accessible_ids[$id]);
|
danielebarchiesi@4
|
254 }
|
danielebarchiesi@4
|
255 }
|
danielebarchiesi@4
|
256
|
danielebarchiesi@4
|
257 foreach ($items as $id => $entity_items) {
|
danielebarchiesi@4
|
258 foreach ($entity_items as $delta => $item) {
|
danielebarchiesi@4
|
259 if (is_array($item) && !empty($item['nid']) && !empty($checked_ids[$item['nid']])) {
|
danielebarchiesi@4
|
260 $items[$id][$delta]['access'] = TRUE;
|
danielebarchiesi@4
|
261 }
|
danielebarchiesi@4
|
262 }
|
danielebarchiesi@4
|
263 }
|
danielebarchiesi@4
|
264 }
|
danielebarchiesi@4
|
265 }
|
danielebarchiesi@4
|
266
|
danielebarchiesi@4
|
267 /**
|
danielebarchiesi@4
|
268 * Implements hook_field_is_empty().
|
danielebarchiesi@4
|
269 */
|
danielebarchiesi@4
|
270 function node_reference_field_is_empty($item, $field) {
|
danielebarchiesi@4
|
271 // nid = 0 is empty too, which is exactly what we want.
|
danielebarchiesi@4
|
272 return empty($item['nid']);
|
danielebarchiesi@4
|
273 }
|
danielebarchiesi@4
|
274
|
danielebarchiesi@4
|
275 /**
|
danielebarchiesi@4
|
276 * Implements hook_field_formatter_info().
|
danielebarchiesi@4
|
277 */
|
danielebarchiesi@4
|
278 function node_reference_field_formatter_info() {
|
danielebarchiesi@4
|
279 $ret = array(
|
danielebarchiesi@4
|
280 'node_reference_default' => array(
|
danielebarchiesi@4
|
281 'label' => t('Title (link)'),
|
danielebarchiesi@4
|
282 'description' => t('Display the title of the referenced node as a link to the node page.'),
|
danielebarchiesi@4
|
283 'field types' => array('node_reference'),
|
danielebarchiesi@4
|
284 ),
|
danielebarchiesi@4
|
285 'node_reference_plain' => array(
|
danielebarchiesi@4
|
286 'label' => t('Title (no link)'),
|
danielebarchiesi@4
|
287 'description' => t('Display the title of the referenced node as plain text.'),
|
danielebarchiesi@4
|
288 'field types' => array('node_reference'),
|
danielebarchiesi@4
|
289 ),
|
danielebarchiesi@4
|
290 'node_reference_node' => array(
|
danielebarchiesi@4
|
291 'label' => t('Rendered node'),
|
danielebarchiesi@4
|
292 'description' => t('Display the referenced node in a specific view mode'),
|
danielebarchiesi@4
|
293 'field types' => array('node_reference'),
|
danielebarchiesi@4
|
294 'settings' => array('node_reference_view_mode' => 'full'),
|
danielebarchiesi@4
|
295 ),
|
danielebarchiesi@4
|
296 'node_reference_nid' => array(
|
danielebarchiesi@4
|
297 'label' => t('Node ID'),
|
danielebarchiesi@4
|
298 'description' => t('Display the referenced node ID'),
|
danielebarchiesi@4
|
299 'field types' => array('node_reference'),
|
danielebarchiesi@4
|
300 ),
|
danielebarchiesi@4
|
301 'node_reference_path' => array(
|
danielebarchiesi@4
|
302 'label' => t('URL as plain text'),
|
danielebarchiesi@4
|
303 'description' => t('Display the URL of the referenced node'),
|
danielebarchiesi@4
|
304 'field types' => array('node_reference'),
|
danielebarchiesi@4
|
305 'settings' => array(
|
danielebarchiesi@4
|
306 'alias' => TRUE,
|
danielebarchiesi@4
|
307 'absolute' => FALSE
|
danielebarchiesi@4
|
308 ),
|
danielebarchiesi@4
|
309 ),
|
danielebarchiesi@4
|
310 );
|
danielebarchiesi@4
|
311 return $ret;
|
danielebarchiesi@4
|
312 }
|
danielebarchiesi@4
|
313
|
danielebarchiesi@4
|
314 /**
|
danielebarchiesi@4
|
315 * Implements hook_field_formatter_settings_form().
|
danielebarchiesi@4
|
316 */
|
danielebarchiesi@4
|
317 function node_reference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
|
danielebarchiesi@4
|
318 $display = $instance['display'][$view_mode];
|
danielebarchiesi@4
|
319 $settings = $display['settings'];
|
danielebarchiesi@4
|
320
|
danielebarchiesi@4
|
321 $element = array();
|
danielebarchiesi@4
|
322
|
danielebarchiesi@4
|
323 switch ($display['type']) {
|
danielebarchiesi@4
|
324 case 'node_reference_node':
|
danielebarchiesi@4
|
325 $entity_info = entity_get_info('node');
|
danielebarchiesi@4
|
326 $modes = $entity_info['view modes'];
|
danielebarchiesi@4
|
327 $options = array();
|
danielebarchiesi@4
|
328 foreach ($modes as $name => $mode) {
|
danielebarchiesi@4
|
329 $options[$name] = $mode['label'];
|
danielebarchiesi@4
|
330 }
|
danielebarchiesi@4
|
331 $element['node_reference_view_mode'] = array(
|
danielebarchiesi@4
|
332 '#title' => t('View mode'),
|
danielebarchiesi@4
|
333 '#type' => 'select',
|
danielebarchiesi@4
|
334 '#options' => $options,
|
danielebarchiesi@4
|
335 '#default_value' => $settings['node_reference_view_mode'],
|
danielebarchiesi@4
|
336 // Never empty, so no #empty_option
|
danielebarchiesi@4
|
337 );
|
danielebarchiesi@4
|
338 break;
|
danielebarchiesi@4
|
339
|
danielebarchiesi@4
|
340 case 'node_reference_path':
|
danielebarchiesi@4
|
341 $element['alias'] = array(
|
danielebarchiesi@4
|
342 '#type' => 'checkbox',
|
danielebarchiesi@4
|
343 '#title' => t('Display the aliased path (if exists) instead of the system path'),
|
danielebarchiesi@4
|
344 '#default_value' => $settings['alias'],
|
danielebarchiesi@4
|
345 );
|
danielebarchiesi@4
|
346 $element['absolute'] = array(
|
danielebarchiesi@4
|
347 '#type' => 'checkbox',
|
danielebarchiesi@4
|
348 '#title' => t('Display an absolute URL'),
|
danielebarchiesi@4
|
349 '#default_value' => $settings['absolute'],
|
danielebarchiesi@4
|
350 );
|
danielebarchiesi@4
|
351 break;
|
danielebarchiesi@4
|
352 }
|
danielebarchiesi@4
|
353
|
danielebarchiesi@4
|
354 return $element;
|
danielebarchiesi@4
|
355 }
|
danielebarchiesi@4
|
356
|
danielebarchiesi@4
|
357 /**
|
danielebarchiesi@4
|
358 * Implements hook_field_formatter_settings_summary().
|
danielebarchiesi@4
|
359 */
|
danielebarchiesi@4
|
360 function node_reference_field_formatter_settings_summary($field, $instance, $view_mode) {
|
danielebarchiesi@4
|
361 $display = $instance['display'][$view_mode];
|
danielebarchiesi@4
|
362 $settings = $display['settings'];
|
danielebarchiesi@4
|
363 $summary = array();
|
danielebarchiesi@4
|
364
|
danielebarchiesi@4
|
365 switch ($display['type']) {
|
danielebarchiesi@4
|
366 case 'node_reference_node':
|
danielebarchiesi@4
|
367 $entity_info = entity_get_info('node');
|
danielebarchiesi@4
|
368 $modes = $entity_info['view modes'];
|
danielebarchiesi@4
|
369 $mode = $modes[$settings['node_reference_view_mode']]['label'];
|
danielebarchiesi@4
|
370 $summary[] = t('View mode: %mode', array('%mode' => $mode));
|
danielebarchiesi@4
|
371 break;
|
danielebarchiesi@4
|
372
|
danielebarchiesi@4
|
373 case 'node_reference_path':
|
danielebarchiesi@4
|
374 $summary[] = t('Aliased path: %yes_no', array('%yes_no' => $settings['alias'] ? t('Yes') : t('No')));
|
danielebarchiesi@4
|
375 $summary[] = t('Absolute URL: %yes_no', array('%yes_no' => $settings['absolute'] ? t('Yes') : t('No')));
|
danielebarchiesi@4
|
376 break;
|
danielebarchiesi@4
|
377 }
|
danielebarchiesi@4
|
378
|
danielebarchiesi@4
|
379 return implode('<br />', $summary);
|
danielebarchiesi@4
|
380 }
|
danielebarchiesi@4
|
381
|
danielebarchiesi@4
|
382 /**
|
danielebarchiesi@4
|
383 * Implements hook_field_formatter_prepare_view().
|
danielebarchiesi@4
|
384 *
|
danielebarchiesi@4
|
385 * Preload all nodes referenced by items using 'full entity' formatters.
|
danielebarchiesi@4
|
386 */
|
danielebarchiesi@4
|
387 function node_reference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
|
danielebarchiesi@4
|
388 // Load the referenced nodes, except for the 'node_reference_nid' which does
|
danielebarchiesi@4
|
389 // not need full objects.
|
danielebarchiesi@4
|
390
|
danielebarchiesi@4
|
391 // Collect ids to load.
|
danielebarchiesi@4
|
392 $ids = array();
|
danielebarchiesi@4
|
393 foreach ($displays as $id => $display) {
|
danielebarchiesi@4
|
394 if ($display['type'] != 'node_reference_nid') {
|
danielebarchiesi@4
|
395 foreach ($items[$id] as $delta => $item) {
|
danielebarchiesi@4
|
396 if ($item['access']) {
|
danielebarchiesi@4
|
397 $ids[$item['nid']] = $item['nid'];
|
danielebarchiesi@4
|
398 }
|
danielebarchiesi@4
|
399 }
|
danielebarchiesi@4
|
400 }
|
danielebarchiesi@4
|
401 }
|
danielebarchiesi@4
|
402 $entities = node_load_multiple($ids);
|
danielebarchiesi@4
|
403
|
danielebarchiesi@4
|
404 // Add the loaded nodes to the items.
|
danielebarchiesi@4
|
405 foreach ($displays as $id => $display) {
|
danielebarchiesi@4
|
406 if ($display['type'] != 'node_reference_nid') {
|
danielebarchiesi@4
|
407 foreach ($items[$id] as $delta => $item) {
|
danielebarchiesi@4
|
408 if ($item['access']) {
|
danielebarchiesi@4
|
409 $items[$id][$delta]['node'] = $entities[$item['nid']];
|
danielebarchiesi@4
|
410 }
|
danielebarchiesi@4
|
411 }
|
danielebarchiesi@4
|
412 }
|
danielebarchiesi@4
|
413 }
|
danielebarchiesi@4
|
414 }
|
danielebarchiesi@4
|
415
|
danielebarchiesi@4
|
416 /**
|
danielebarchiesi@4
|
417 * Implements hook_field_formatter_view().
|
danielebarchiesi@4
|
418 */
|
danielebarchiesi@4
|
419 function node_reference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
|
danielebarchiesi@4
|
420 $settings = $display['settings'];
|
danielebarchiesi@4
|
421 $result = array();
|
danielebarchiesi@4
|
422
|
danielebarchiesi@4
|
423 switch ($display['type']) {
|
danielebarchiesi@4
|
424 case 'node_reference_default':
|
danielebarchiesi@4
|
425 case 'node_reference_plain':
|
danielebarchiesi@4
|
426 foreach ($items as $delta => $item) {
|
danielebarchiesi@4
|
427 if ($item['access']) {
|
danielebarchiesi@4
|
428 $node = $item['node'];
|
danielebarchiesi@4
|
429 $label = entity_label('node', $node);
|
danielebarchiesi@4
|
430 if ($display['type'] == 'node_reference_default') {
|
danielebarchiesi@4
|
431 $uri = entity_uri('node', $node);
|
danielebarchiesi@4
|
432 $result[$delta] = array(
|
danielebarchiesi@4
|
433 '#type' => 'link',
|
danielebarchiesi@4
|
434 '#title' => $label,
|
danielebarchiesi@4
|
435 '#href' => $uri['path'],
|
danielebarchiesi@4
|
436 '#options' => $uri['options'],
|
danielebarchiesi@4
|
437 );
|
danielebarchiesi@4
|
438 }
|
danielebarchiesi@4
|
439 else {
|
danielebarchiesi@4
|
440 $result[$delta] = array(
|
danielebarchiesi@4
|
441 '#markup' => check_plain($label),
|
danielebarchiesi@4
|
442 );
|
danielebarchiesi@4
|
443 }
|
danielebarchiesi@4
|
444 if (!$node->status) {
|
danielebarchiesi@4
|
445 $result[$delta]['#prefix'] = '<span class="node-unpublished">';
|
danielebarchiesi@4
|
446 $result[$delta]['#suffix'] = '</span>';
|
danielebarchiesi@4
|
447 }
|
danielebarchiesi@4
|
448 }
|
danielebarchiesi@4
|
449 }
|
danielebarchiesi@4
|
450 break;
|
danielebarchiesi@4
|
451
|
danielebarchiesi@4
|
452 case 'node_reference_node':
|
danielebarchiesi@4
|
453 // To prevent infinite recursion caused by reference cycles, we store
|
danielebarchiesi@4
|
454 // diplayed nodes in a recursion queue.
|
danielebarchiesi@4
|
455 $recursion_queue = &drupal_static(__FUNCTION__, array());
|
danielebarchiesi@4
|
456
|
danielebarchiesi@4
|
457 // If no 'referencing entity' is set, we are starting a new 'reference
|
danielebarchiesi@4
|
458 // thread' and need to reset the queue.
|
danielebarchiesi@4
|
459 // @todo Bug: $entity->referencing_entity on nodes referenced in a different
|
danielebarchiesi@4
|
460 // thread on the page. E.g: 1 references 1+2 / 2 references 1+2 / visit homepage.
|
danielebarchiesi@4
|
461 // We'd need a more accurate way...
|
danielebarchiesi@4
|
462 if (!isset($entity->referencing_entity)) {
|
danielebarchiesi@4
|
463 $recursion_queue = array();
|
danielebarchiesi@4
|
464 }
|
danielebarchiesi@4
|
465
|
danielebarchiesi@4
|
466 // The recursion queue only needs to track nodes.
|
danielebarchiesi@4
|
467 if ($entity_type == 'node') {
|
danielebarchiesi@4
|
468 list($id) = entity_extract_ids($entity_type, $entity);
|
danielebarchiesi@4
|
469 $recursion_queue[$id] = $id;
|
danielebarchiesi@4
|
470 }
|
danielebarchiesi@4
|
471
|
danielebarchiesi@4
|
472 // Check the recursion queue to determine which nodes should be fully
|
danielebarchiesi@4
|
473 // displayed, and which nodes will only be displayed as a title.
|
danielebarchiesi@4
|
474 $nodes_display = array();
|
danielebarchiesi@4
|
475 foreach ($items as $delta => $item) {
|
danielebarchiesi@4
|
476 if ($item['access'] && !isset($recursion_queue[$item['nid']])) {
|
danielebarchiesi@4
|
477 $nodes_display[$item['nid']] = $item['node'];
|
danielebarchiesi@4
|
478 }
|
danielebarchiesi@4
|
479 }
|
danielebarchiesi@4
|
480
|
danielebarchiesi@4
|
481 // Load and build the fully displayed nodes.
|
danielebarchiesi@4
|
482 if ($nodes_display) {
|
danielebarchiesi@4
|
483 foreach ($nodes_display as $nid => $node) {
|
danielebarchiesi@4
|
484 $nodes_display[$nid]->referencing_entity = $entity;
|
danielebarchiesi@4
|
485 $nodes_display[$nid]->referencing_field = $field['field_name'];
|
danielebarchiesi@4
|
486 }
|
danielebarchiesi@4
|
487 $nodes_built = node_view_multiple($nodes_display, $settings['node_reference_view_mode']);
|
danielebarchiesi@4
|
488 }
|
danielebarchiesi@4
|
489
|
danielebarchiesi@4
|
490 // Assemble the render array.
|
danielebarchiesi@4
|
491 foreach ($items as $delta => $item) {
|
danielebarchiesi@4
|
492 if ($item['access']) {
|
danielebarchiesi@4
|
493 if (isset($nodes_display[$item['nid']])) {
|
danielebarchiesi@4
|
494 $result[$delta] = $nodes_built['nodes'][$item['nid']];
|
danielebarchiesi@4
|
495 }
|
danielebarchiesi@4
|
496 else {
|
danielebarchiesi@4
|
497 $node = $item['node'];
|
danielebarchiesi@4
|
498 $label = entity_label('node', $node);
|
danielebarchiesi@4
|
499 $uri = entity_uri('node', $node);
|
danielebarchiesi@4
|
500 $result[$delta] = array(
|
danielebarchiesi@4
|
501 '#type' => 'link',
|
danielebarchiesi@4
|
502 '#title' => $label,
|
danielebarchiesi@4
|
503 '#href' => $uri['path'],
|
danielebarchiesi@4
|
504 '#options' => $uri['options'],
|
danielebarchiesi@4
|
505 );
|
danielebarchiesi@4
|
506 if (!$node->status) {
|
danielebarchiesi@4
|
507 $result[$delta]['#prefix'] = '<span class="node-unpublished">';
|
danielebarchiesi@4
|
508 $result[$delta]['#suffix'] = '</span>';
|
danielebarchiesi@4
|
509 }
|
danielebarchiesi@4
|
510 }
|
danielebarchiesi@4
|
511 }
|
danielebarchiesi@4
|
512 }
|
danielebarchiesi@4
|
513 break;
|
danielebarchiesi@4
|
514
|
danielebarchiesi@4
|
515 case 'node_reference_nid':
|
danielebarchiesi@4
|
516 foreach ($items as $delta => $item) {
|
danielebarchiesi@4
|
517 if ($item['access']) {
|
danielebarchiesi@4
|
518 $result[$delta] = array(
|
danielebarchiesi@4
|
519 '#markup' => $item['nid'],
|
danielebarchiesi@4
|
520 );
|
danielebarchiesi@4
|
521 }
|
danielebarchiesi@4
|
522 }
|
danielebarchiesi@4
|
523 break;
|
danielebarchiesi@4
|
524
|
danielebarchiesi@4
|
525 case 'node_reference_path':
|
danielebarchiesi@4
|
526 foreach ($items as $delta => $item) {
|
danielebarchiesi@4
|
527 if ($item['access']) {
|
danielebarchiesi@4
|
528 $uri = entity_uri('node', $item['node']);
|
danielebarchiesi@4
|
529 $options = array(
|
danielebarchiesi@4
|
530 'absolute' => $settings['absolute'],
|
danielebarchiesi@4
|
531 'alias' => !$settings['alias'],
|
danielebarchiesi@4
|
532 );
|
danielebarchiesi@4
|
533
|
danielebarchiesi@4
|
534 $options += $uri['options'];
|
danielebarchiesi@4
|
535 $result[$delta] = array(
|
danielebarchiesi@4
|
536 '#markup' => url($uri['path'], $options),
|
danielebarchiesi@4
|
537 );
|
danielebarchiesi@4
|
538 }
|
danielebarchiesi@4
|
539 }
|
danielebarchiesi@4
|
540 break;
|
danielebarchiesi@4
|
541 }
|
danielebarchiesi@4
|
542
|
danielebarchiesi@4
|
543 return $result;
|
danielebarchiesi@4
|
544 }
|
danielebarchiesi@4
|
545
|
danielebarchiesi@4
|
546 /**
|
danielebarchiesi@4
|
547 * Implements hook_field_widget_info().
|
danielebarchiesi@4
|
548 */
|
danielebarchiesi@4
|
549 function node_reference_field_widget_info() {
|
danielebarchiesi@4
|
550 return array(
|
danielebarchiesi@4
|
551 'node_reference_autocomplete' => array(
|
danielebarchiesi@4
|
552 'label' => t('Autocomplete text field'),
|
danielebarchiesi@4
|
553 'description' => t('Display the list of referenceable nodes as a textfield with autocomplete behaviour.'),
|
danielebarchiesi@4
|
554 'field types' => array('node_reference'),
|
danielebarchiesi@4
|
555 'settings' => array(
|
danielebarchiesi@4
|
556 'autocomplete_match' => 'contains',
|
danielebarchiesi@4
|
557 'size' => 60,
|
danielebarchiesi@4
|
558 'autocomplete_path' => 'node_reference/autocomplete',
|
danielebarchiesi@4
|
559 ),
|
danielebarchiesi@4
|
560 ),
|
danielebarchiesi@4
|
561 );
|
danielebarchiesi@4
|
562 }
|
danielebarchiesi@4
|
563
|
danielebarchiesi@4
|
564 /**
|
danielebarchiesi@4
|
565 * Implements hook_field_widget_info_alter().
|
danielebarchiesi@4
|
566 */
|
danielebarchiesi@4
|
567 function node_reference_field_widget_info_alter(&$info) {
|
danielebarchiesi@4
|
568 $info['options_select']['field types'][] = 'node_reference';
|
danielebarchiesi@4
|
569 $info['options_buttons']['field types'][] = 'node_reference';
|
danielebarchiesi@4
|
570 }
|
danielebarchiesi@4
|
571
|
danielebarchiesi@4
|
572 /**
|
danielebarchiesi@4
|
573 * Implements hook_field_widget_settings_form().
|
danielebarchiesi@4
|
574 */
|
danielebarchiesi@4
|
575 function node_reference_field_widget_settings_form($field, $instance) {
|
danielebarchiesi@4
|
576 $widget = $instance['widget'];
|
danielebarchiesi@4
|
577 $defaults = field_info_widget_settings($widget['type']);
|
danielebarchiesi@4
|
578 $settings = array_merge($defaults, $widget['settings']);
|
danielebarchiesi@4
|
579
|
danielebarchiesi@4
|
580 $form = array();
|
danielebarchiesi@4
|
581 if ($widget['type'] == 'node_reference_autocomplete') {
|
danielebarchiesi@4
|
582 $form['autocomplete_match'] = array(
|
danielebarchiesi@4
|
583 '#type' => 'select',
|
danielebarchiesi@4
|
584 '#title' => t('Autocomplete matching'),
|
danielebarchiesi@4
|
585 '#default_value' => $settings['autocomplete_match'],
|
danielebarchiesi@4
|
586 '#options' => array(
|
danielebarchiesi@4
|
587 'starts_with' => t('Starts with'),
|
danielebarchiesi@4
|
588 'contains' => t('Contains'),
|
danielebarchiesi@4
|
589 ),
|
danielebarchiesi@4
|
590 '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of nodes.'),
|
danielebarchiesi@4
|
591 );
|
danielebarchiesi@4
|
592 $form['size'] = array(
|
danielebarchiesi@4
|
593 '#type' => 'textfield',
|
danielebarchiesi@4
|
594 '#title' => t('Size of textfield'),
|
danielebarchiesi@4
|
595 '#default_value' => $settings['size'],
|
danielebarchiesi@4
|
596 '#element_validate' => array('_element_validate_integer_positive'),
|
danielebarchiesi@4
|
597 '#required' => TRUE,
|
danielebarchiesi@4
|
598 );
|
danielebarchiesi@4
|
599 }
|
danielebarchiesi@4
|
600 return $form;
|
danielebarchiesi@4
|
601 }
|
danielebarchiesi@4
|
602
|
danielebarchiesi@4
|
603 /**
|
danielebarchiesi@4
|
604 * Implements hook_field_widget_form().
|
danielebarchiesi@4
|
605 */
|
danielebarchiesi@4
|
606 function node_reference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
|
danielebarchiesi@4
|
607 switch ($instance['widget']['type']) {
|
danielebarchiesi@4
|
608 case 'node_reference_autocomplete':
|
danielebarchiesi@4
|
609 $element += array(
|
danielebarchiesi@4
|
610 '#type' => 'textfield',
|
danielebarchiesi@4
|
611 '#default_value' => isset($items[$delta]['nid']) ? $items[$delta]['nid'] : NULL,
|
danielebarchiesi@4
|
612 '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
|
danielebarchiesi@4
|
613 '#size' => $instance['widget']['settings']['size'],
|
danielebarchiesi@4
|
614 '#maxlength' => NULL,
|
danielebarchiesi@4
|
615 '#element_validate' => array('node_reference_autocomplete_validate'),
|
danielebarchiesi@4
|
616 '#value_callback' => 'node_reference_autocomplete_value',
|
danielebarchiesi@4
|
617 );
|
danielebarchiesi@4
|
618 break;
|
danielebarchiesi@4
|
619 }
|
danielebarchiesi@4
|
620
|
danielebarchiesi@4
|
621 return array('nid' => $element);
|
danielebarchiesi@4
|
622 }
|
danielebarchiesi@4
|
623
|
danielebarchiesi@4
|
624 /**
|
danielebarchiesi@4
|
625 * Value callback for a node_reference autocomplete element.
|
danielebarchiesi@4
|
626 *
|
danielebarchiesi@4
|
627 * Replace the node nid with a node title.
|
danielebarchiesi@4
|
628 */
|
danielebarchiesi@4
|
629 function node_reference_autocomplete_value($element, $input = FALSE, $form_state) {
|
danielebarchiesi@4
|
630 if ($input === FALSE) {
|
danielebarchiesi@4
|
631 // We're building the displayed 'default value': expand the raw nid into
|
danielebarchiesi@4
|
632 // "node title [nid:n]".
|
danielebarchiesi@4
|
633 $nid = $element['#default_value'];
|
danielebarchiesi@4
|
634 if (!empty($nid)) {
|
danielebarchiesi@4
|
635 $q = db_select('node', 'n');
|
danielebarchiesi@4
|
636 $node_title_alias = $q->addField('n', 'title');
|
danielebarchiesi@4
|
637 $q->addTag('node_access')
|
danielebarchiesi@4
|
638 ->condition('n.nid', $nid)
|
danielebarchiesi@4
|
639 ->range(0, 1);
|
danielebarchiesi@4
|
640 $result = $q->execute();
|
danielebarchiesi@4
|
641 // @todo If no result (node doesn't exist or no access).
|
danielebarchiesi@4
|
642 $value = $result->fetchField();
|
danielebarchiesi@4
|
643 $value .= ' [nid:' . $nid . ']';
|
danielebarchiesi@4
|
644 return $value;
|
danielebarchiesi@4
|
645 }
|
danielebarchiesi@4
|
646 }
|
danielebarchiesi@4
|
647 }
|
danielebarchiesi@4
|
648
|
danielebarchiesi@4
|
649 /**
|
danielebarchiesi@4
|
650 * Validation callback for a node_reference autocomplete element.
|
danielebarchiesi@4
|
651 */
|
danielebarchiesi@4
|
652 function node_reference_autocomplete_validate($element, &$form_state, $form) {
|
danielebarchiesi@4
|
653 $field = field_widget_field($element, $form_state);
|
danielebarchiesi@4
|
654 $instance = field_widget_instance($element, $form_state);
|
danielebarchiesi@4
|
655
|
danielebarchiesi@4
|
656 $value = $element['#value'];
|
danielebarchiesi@4
|
657 $nid = NULL;
|
danielebarchiesi@4
|
658
|
danielebarchiesi@4
|
659 if (!empty($value)) {
|
danielebarchiesi@4
|
660 // Check whether we have an explicit "[nid:n]" input.
|
danielebarchiesi@4
|
661 preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $value, $matches);
|
danielebarchiesi@4
|
662 if (!empty($matches)) {
|
danielebarchiesi@4
|
663 // Explicit nid. Check that the 'title' part matches the actual title for
|
danielebarchiesi@4
|
664 // the nid.
|
danielebarchiesi@4
|
665 list(, $title, $nid) = $matches;
|
danielebarchiesi@4
|
666 if (!empty($title)) {
|
danielebarchiesi@4
|
667 $real_title = db_select('node', 'n')
|
danielebarchiesi@4
|
668 ->fields('n', array('title'))
|
danielebarchiesi@4
|
669 ->condition('n.nid', $nid)
|
danielebarchiesi@4
|
670 ->execute()
|
danielebarchiesi@4
|
671 ->fetchField();
|
danielebarchiesi@4
|
672 if (trim($title) != trim($real_title)) {
|
danielebarchiesi@4
|
673 form_error($element, t('%name: title mismatch. Please check your selection.', array('%name' => $instance['label'])));
|
danielebarchiesi@4
|
674 }
|
danielebarchiesi@4
|
675 }
|
danielebarchiesi@4
|
676 }
|
danielebarchiesi@4
|
677 else {
|
danielebarchiesi@4
|
678 // No explicit nid (the submitted value was not populated by autocomplete
|
danielebarchiesi@4
|
679 // selection). Get the nid of a referencable node from the entered title.
|
danielebarchiesi@4
|
680 $options = array(
|
danielebarchiesi@4
|
681 'string' => $value,
|
danielebarchiesi@4
|
682 'match' => 'equals',
|
danielebarchiesi@4
|
683 'limit' => 1,
|
danielebarchiesi@4
|
684 );
|
danielebarchiesi@4
|
685 $references = node_reference_potential_references($field, $options);
|
danielebarchiesi@4
|
686 if ($references) {
|
danielebarchiesi@4
|
687 // @todo The best thing would be to present the user with an
|
danielebarchiesi@4
|
688 // additional form, allowing the user to choose between valid
|
danielebarchiesi@4
|
689 // candidates with the same title. ATM, we pick the first
|
danielebarchiesi@4
|
690 // matching candidate...
|
danielebarchiesi@4
|
691 $nid = key($references);
|
danielebarchiesi@4
|
692 }
|
danielebarchiesi@4
|
693 else {
|
danielebarchiesi@4
|
694 form_error($element, t('%name: found no valid post with that title.', array('%name' => $instance['label'])));
|
danielebarchiesi@4
|
695 }
|
danielebarchiesi@4
|
696 }
|
danielebarchiesi@4
|
697 }
|
danielebarchiesi@4
|
698
|
danielebarchiesi@4
|
699 // Set the element's value as the node id that was extracted from the entered
|
danielebarchiesi@4
|
700 // input.
|
danielebarchiesi@4
|
701 form_set_value($element, $nid, $form_state);
|
danielebarchiesi@4
|
702 }
|
danielebarchiesi@4
|
703
|
danielebarchiesi@4
|
704 /**
|
danielebarchiesi@4
|
705 * Implements hook_field_widget_error().
|
danielebarchiesi@4
|
706 */
|
danielebarchiesi@4
|
707 function node_reference_field_widget_error($element, $error, $form, &$form_state) {
|
danielebarchiesi@4
|
708 form_error($element['nid'], $error['message']);
|
danielebarchiesi@4
|
709 }
|
danielebarchiesi@4
|
710
|
danielebarchiesi@4
|
711 /**
|
danielebarchiesi@4
|
712 * Builds a list of referenceable nodes suitable for the '#option' FAPI property.
|
danielebarchiesi@4
|
713 *
|
danielebarchiesi@4
|
714 * Warning: the function does NOT take care of encoding or escaping the node
|
danielebarchiesi@4
|
715 * titles. Proper massaging needs to be performed by the caller, according to
|
danielebarchiesi@4
|
716 * the destination FAPI '#type' (radios / checkboxes / select).
|
danielebarchiesi@4
|
717 *
|
danielebarchiesi@4
|
718 * @param $field
|
danielebarchiesi@4
|
719 * The field definition.
|
danielebarchiesi@4
|
720 * @param $flat
|
danielebarchiesi@4
|
721 * Whether optgroups are allowed.
|
danielebarchiesi@4
|
722 *
|
danielebarchiesi@4
|
723 * @return
|
danielebarchiesi@4
|
724 * An array of referenceable node titles, keyed by node id. If the $flat
|
danielebarchiesi@4
|
725 * parameter is TRUE, the list might be nested by optgroup first.
|
danielebarchiesi@4
|
726 */
|
danielebarchiesi@4
|
727 function _node_reference_options($field, $flat = TRUE) {
|
danielebarchiesi@4
|
728 $references = node_reference_potential_references($field);
|
danielebarchiesi@4
|
729
|
danielebarchiesi@4
|
730 $options = array();
|
danielebarchiesi@4
|
731 foreach ($references as $key => $value) {
|
danielebarchiesi@4
|
732 // The label, displayed in selects and checkboxes/radios, should have HTML
|
danielebarchiesi@4
|
733 // entities unencoded. The widgets (core's options.module) take care of
|
danielebarchiesi@4
|
734 // applying the relevant filters (strip_tags() or filter_xss()).
|
danielebarchiesi@4
|
735 $label = html_entity_decode($value['rendered'], ENT_QUOTES);
|
danielebarchiesi@4
|
736 if (empty($value['group']) || $flat) {
|
danielebarchiesi@4
|
737 $options[$key] = $label;
|
danielebarchiesi@4
|
738 }
|
danielebarchiesi@4
|
739 else {
|
danielebarchiesi@4
|
740 // The group name, displayed in selects, cannot contain tags, and should
|
danielebarchiesi@4
|
741 // have HTML entities unencoded.
|
danielebarchiesi@4
|
742 $group = html_entity_decode(strip_tags($value['group']), ENT_QUOTES);
|
danielebarchiesi@4
|
743 $options[$group][$key] = $label;
|
danielebarchiesi@4
|
744 }
|
danielebarchiesi@4
|
745 }
|
danielebarchiesi@4
|
746
|
danielebarchiesi@4
|
747 return $options;
|
danielebarchiesi@4
|
748 }
|
danielebarchiesi@4
|
749
|
danielebarchiesi@4
|
750 /**
|
danielebarchiesi@4
|
751 * Retrieves an array of candidate referenceable nodes.
|
danielebarchiesi@4
|
752 *
|
danielebarchiesi@4
|
753 * This info is used in various places (allowed values, autocomplete
|
danielebarchiesi@4
|
754 * results, input validation...). Some of them only need the nids,
|
danielebarchiesi@4
|
755 * others nid + titles, others yet nid + titles + rendered row (for
|
danielebarchiesi@4
|
756 * display in widgets).
|
danielebarchiesi@4
|
757 *
|
danielebarchiesi@4
|
758 * The array we return contains all the potentially needed information,
|
danielebarchiesi@4
|
759 * and lets consumers use the parts they actually need.
|
danielebarchiesi@4
|
760 *
|
danielebarchiesi@4
|
761 * @param $field
|
danielebarchiesi@4
|
762 * The field definition.
|
danielebarchiesi@4
|
763 * @param $options
|
danielebarchiesi@4
|
764 * An array of options to limit the scope of the returned list. The following
|
danielebarchiesi@4
|
765 * key/value pairs are accepted:
|
danielebarchiesi@4
|
766 * - string: string to filter titles on (used by autocomplete).
|
danielebarchiesi@4
|
767 * - match: operator to match the above string against, can be any of:
|
danielebarchiesi@4
|
768 * 'contains', 'equals', 'starts_with'. Defaults to 'contains'.
|
danielebarchiesi@4
|
769 * - ids: array of specific node ids to lookup.
|
danielebarchiesi@4
|
770 * - limit: maximum size of the the result set. Defaults to 0 (no limit).
|
danielebarchiesi@4
|
771 *
|
danielebarchiesi@4
|
772 * @return
|
danielebarchiesi@4
|
773 * An array of valid nodes in the form:
|
danielebarchiesi@4
|
774 * array(
|
danielebarchiesi@4
|
775 * nid => array(
|
danielebarchiesi@4
|
776 * 'title' => The node title,
|
danielebarchiesi@4
|
777 * 'rendered' => The text to display in widgets (can be HTML)
|
danielebarchiesi@4
|
778 * ),
|
danielebarchiesi@4
|
779 * ...
|
danielebarchiesi@4
|
780 * )
|
danielebarchiesi@4
|
781 */
|
danielebarchiesi@4
|
782 function node_reference_potential_references($field, $options = array()) {
|
danielebarchiesi@4
|
783 // Fill in default options.
|
danielebarchiesi@4
|
784 $options += array(
|
danielebarchiesi@4
|
785 'string' => '',
|
danielebarchiesi@4
|
786 'match' => 'contains',
|
danielebarchiesi@4
|
787 'ids' => array(),
|
danielebarchiesi@4
|
788 'limit' => 0,
|
danielebarchiesi@4
|
789 );
|
danielebarchiesi@4
|
790
|
danielebarchiesi@4
|
791 $results = &drupal_static(__FUNCTION__, array());
|
danielebarchiesi@4
|
792
|
danielebarchiesi@4
|
793 // Create unique id for static cache.
|
danielebarchiesi@4
|
794 $cid = $field['field_name'] . ':' . $options['match'] . ':'
|
danielebarchiesi@4
|
795 . ($options['string'] !== '' ? $options['string'] : implode('-', $options['ids']))
|
danielebarchiesi@4
|
796 . ':' . $options['limit'];
|
danielebarchiesi@4
|
797 if (!isset($results[$cid])) {
|
danielebarchiesi@4
|
798 $references = FALSE;
|
danielebarchiesi@4
|
799 if (module_exists('views') && !empty($field['settings']['view']['view_name'])) {
|
danielebarchiesi@4
|
800 $references = _node_reference_potential_references_views($field, $options);
|
danielebarchiesi@4
|
801 }
|
danielebarchiesi@4
|
802
|
danielebarchiesi@4
|
803 if ($references === FALSE) {
|
danielebarchiesi@4
|
804 $references = _node_reference_potential_references_standard($field, $options);
|
danielebarchiesi@4
|
805 }
|
danielebarchiesi@4
|
806
|
danielebarchiesi@4
|
807 // Store the results.
|
danielebarchiesi@4
|
808 $results[$cid] = !empty($references) ? $references : array();
|
danielebarchiesi@4
|
809 }
|
danielebarchiesi@4
|
810
|
danielebarchiesi@4
|
811 return $results[$cid];
|
danielebarchiesi@4
|
812 }
|
danielebarchiesi@4
|
813
|
danielebarchiesi@4
|
814 /**
|
danielebarchiesi@4
|
815 * Helper function for node_reference_potential_references().
|
danielebarchiesi@4
|
816 *
|
danielebarchiesi@4
|
817 * Case of Views-defined referenceable nodes.
|
danielebarchiesi@4
|
818 */
|
danielebarchiesi@4
|
819 function _node_reference_potential_references_views($field, $options) {
|
danielebarchiesi@4
|
820 $settings = $field['settings']['view'];
|
danielebarchiesi@4
|
821 $options['title_field'] = 'title';
|
danielebarchiesi@4
|
822 return references_potential_references_view('node', $settings['view_name'], $settings['display_name'], $settings['args'], $options);
|
danielebarchiesi@4
|
823 }
|
danielebarchiesi@4
|
824
|
danielebarchiesi@4
|
825 /**
|
danielebarchiesi@4
|
826 * Helper function for node_reference_potential_references().
|
danielebarchiesi@4
|
827 *
|
danielebarchiesi@4
|
828 * List of referenceable nodes defined by content types.
|
danielebarchiesi@4
|
829 */
|
danielebarchiesi@4
|
830 function _node_reference_potential_references_standard($field, $options) {
|
danielebarchiesi@4
|
831 // Avoid useless work
|
danielebarchiesi@4
|
832 if (!count($field['settings']['referenceable_types'])) {
|
danielebarchiesi@4
|
833 return array();
|
danielebarchiesi@4
|
834 }
|
danielebarchiesi@4
|
835
|
danielebarchiesi@4
|
836 $query = db_select('node', 'n');
|
danielebarchiesi@4
|
837 $node_nid_alias = $query->addField('n', 'nid');
|
danielebarchiesi@4
|
838 $node_title_alias = $query->addField('n', 'title', 'node_title');
|
danielebarchiesi@4
|
839 $node_type_alias = $query->addField('n', 'type', 'node_type');
|
danielebarchiesi@4
|
840 $query->addTag('node_access')
|
danielebarchiesi@4
|
841 ->addMetaData('id', ' _node_reference_potential_references_standard')
|
danielebarchiesi@4
|
842 ->addMetaData('field', $field)
|
danielebarchiesi@4
|
843 ->addMetaData('options', $options);
|
danielebarchiesi@4
|
844
|
danielebarchiesi@4
|
845 if (is_array($field['settings']['referenceable_types'])) {
|
danielebarchiesi@4
|
846 $query->condition('n.type', $field['settings']['referenceable_types'], 'IN');
|
danielebarchiesi@4
|
847 }
|
danielebarchiesi@4
|
848
|
danielebarchiesi@4
|
849 if ($options['string'] !== '') {
|
danielebarchiesi@4
|
850 switch ($options['match']) {
|
danielebarchiesi@4
|
851 case 'contains':
|
danielebarchiesi@4
|
852 $query->condition('n.title', '%' . $options['string'] . '%', 'LIKE');
|
danielebarchiesi@4
|
853 break;
|
danielebarchiesi@4
|
854
|
danielebarchiesi@4
|
855 case 'starts_with':
|
danielebarchiesi@4
|
856 $query->condition('n.title', $options['string'] . '%', 'LIKE');
|
danielebarchiesi@4
|
857 break;
|
danielebarchiesi@4
|
858
|
danielebarchiesi@4
|
859 case 'equals':
|
danielebarchiesi@4
|
860 default: // no match type or incorrect match type: use "="
|
danielebarchiesi@4
|
861 $query->condition('n.title', $options['string']);
|
danielebarchiesi@4
|
862 break;
|
danielebarchiesi@4
|
863 }
|
danielebarchiesi@4
|
864 }
|
danielebarchiesi@4
|
865
|
danielebarchiesi@4
|
866 if ($options['ids']) {
|
danielebarchiesi@4
|
867 $query->condition('n.nid', $options['ids'], 'IN');
|
danielebarchiesi@4
|
868 }
|
danielebarchiesi@4
|
869
|
danielebarchiesi@4
|
870 if ($options['limit']) {
|
danielebarchiesi@4
|
871 $query->range(0, $options['limit']);
|
danielebarchiesi@4
|
872 }
|
danielebarchiesi@4
|
873
|
danielebarchiesi@4
|
874 $query
|
danielebarchiesi@4
|
875 ->orderBy($node_title_alias)
|
danielebarchiesi@4
|
876 ->orderBy($node_type_alias);
|
danielebarchiesi@4
|
877
|
danielebarchiesi@4
|
878 $result = $query->execute()->fetchAll();
|
danielebarchiesi@4
|
879 $references = array();
|
danielebarchiesi@4
|
880 foreach ($result as $node) {
|
danielebarchiesi@4
|
881 $references[$node->nid] = array(
|
danielebarchiesi@4
|
882 'title' => $node->node_title,
|
danielebarchiesi@4
|
883 'rendered' => check_plain($node->node_title),
|
danielebarchiesi@4
|
884 );
|
danielebarchiesi@4
|
885 }
|
danielebarchiesi@4
|
886 return $references;
|
danielebarchiesi@4
|
887 }
|
danielebarchiesi@4
|
888
|
danielebarchiesi@4
|
889 /**
|
danielebarchiesi@4
|
890 * Menu callback for the autocomplete results.
|
danielebarchiesi@4
|
891 */
|
danielebarchiesi@4
|
892 function node_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
|
danielebarchiesi@4
|
893 $field = field_info_field($field_name);
|
danielebarchiesi@4
|
894 $instance = field_info_instance($entity_type, $field_name, $bundle);
|
danielebarchiesi@4
|
895
|
danielebarchiesi@4
|
896 $options = array(
|
danielebarchiesi@4
|
897 'string' => $string,
|
danielebarchiesi@4
|
898 'match' => $instance['widget']['settings']['autocomplete_match'],
|
danielebarchiesi@4
|
899 'limit' => 10,
|
danielebarchiesi@4
|
900 );
|
danielebarchiesi@4
|
901 $references = node_reference_potential_references($field, $options);
|
danielebarchiesi@4
|
902
|
danielebarchiesi@4
|
903 $matches = array();
|
danielebarchiesi@4
|
904 foreach ($references as $id => $row) {
|
danielebarchiesi@4
|
905 // Markup is fine in autocompletion results (might happen when rendered
|
danielebarchiesi@4
|
906 // through Views) but we want to remove hyperlinks.
|
danielebarchiesi@4
|
907 $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
|
danielebarchiesi@4
|
908 // Add a class wrapper for a few required CSS overrides.
|
danielebarchiesi@4
|
909 $matches[$row['title'] . " [nid:$id]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
|
danielebarchiesi@4
|
910 }
|
danielebarchiesi@4
|
911
|
danielebarchiesi@4
|
912 drupal_json_output($matches);
|
danielebarchiesi@4
|
913 }
|
danielebarchiesi@4
|
914
|
danielebarchiesi@4
|
915 /**
|
danielebarchiesi@4
|
916 * Implements hook_node_type_update().
|
danielebarchiesi@4
|
917 *
|
danielebarchiesi@4
|
918 * Reflect type name changes to the 'referenceable types' settings: when
|
danielebarchiesi@4
|
919 * the name of a type changes, the change needs to be reflected in the
|
danielebarchiesi@4
|
920 * "referenceable types" setting for any node_reference field
|
danielebarchiesi@4
|
921 * referencing it.
|
danielebarchiesi@4
|
922 */
|
danielebarchiesi@4
|
923 function node_reference_node_type_update($info) {
|
danielebarchiesi@4
|
924 if (!empty($info->old_type) && $info->old_type != $info->type) {
|
danielebarchiesi@4
|
925 $fields = field_info_fields();
|
danielebarchiesi@4
|
926 foreach ($fields as $field_name => $field) {
|
danielebarchiesi@4
|
927 if ($field['type'] == 'node_reference' && isset($field['settings']['referenceable_types'][$info->old_type])) {
|
danielebarchiesi@4
|
928 $field['settings']['referenceable_types'][$info->type] = empty($field['settings']['referenceable_types'][$info->old_type]) ? 0 : $info->type;
|
danielebarchiesi@4
|
929 unset($field['settings']['referenceable_types'][$info->old_type]);
|
danielebarchiesi@4
|
930 field_update_field($field);
|
danielebarchiesi@4
|
931 }
|
danielebarchiesi@4
|
932 }
|
danielebarchiesi@4
|
933 }
|
danielebarchiesi@4
|
934 }
|
danielebarchiesi@4
|
935
|
danielebarchiesi@4
|
936 /**
|
danielebarchiesi@4
|
937 * Theme preprocess function.
|
danielebarchiesi@4
|
938 *
|
danielebarchiesi@4
|
939 * Allows specific node templates for nodes displayed as values of a
|
danielebarchiesi@4
|
940 * node_reference field with a specific view mode.
|
danielebarchiesi@4
|
941 */
|
danielebarchiesi@4
|
942 function node_reference_preprocess_node(&$vars) {
|
danielebarchiesi@4
|
943 // The 'referencing_field' attribute of the node is added by the
|
danielebarchiesi@4
|
944 // node_reference_node mode formatter (display referenced node
|
danielebarchiesi@4
|
945 // in a specific view mode).
|
danielebarchiesi@4
|
946 if (!empty($vars['node']->referencing_field)) {
|
danielebarchiesi@4
|
947 $node = $vars['node'];
|
danielebarchiesi@4
|
948 $field_name = $node->referencing_field;
|
danielebarchiesi@4
|
949 $vars['theme_hook_suggestions'][] = 'node__node_reference';
|
danielebarchiesi@4
|
950 $vars['theme_hook_suggestions'][] = 'node__node_reference__' . $field_name;
|
danielebarchiesi@4
|
951 $vars['theme_hook_suggestions'][] = 'node__node_reference__' . $node->type;
|
danielebarchiesi@4
|
952 $vars['theme_hook_suggestions'][] = 'node__node_reference__' . $field_name . '__' . $node->type;
|
danielebarchiesi@4
|
953 }
|
danielebarchiesi@4
|
954 }
|
danielebarchiesi@4
|
955
|
danielebarchiesi@4
|
956 /**
|
danielebarchiesi@4
|
957 * Implements hook_field_prepare_translation().
|
danielebarchiesi@4
|
958 *
|
danielebarchiesi@4
|
959 * When preparing a translation, load any translations of existing
|
danielebarchiesi@4
|
960 * references.
|
danielebarchiesi@4
|
961 */
|
danielebarchiesi@4
|
962 function node_reference_field_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items, $source_entity, $source_langcode) {
|
danielebarchiesi@4
|
963 if (isset($items) && is_array($items)) {
|
danielebarchiesi@4
|
964 // Match each reference with its matching translation, if it exists.
|
danielebarchiesi@4
|
965 foreach ($items as $key => $item) {
|
danielebarchiesi@4
|
966 $reference_node = node_load($item['nid']);
|
danielebarchiesi@4
|
967 $items[$key]['nid'] = node_reference_find_translation($reference_node, $entity->language);
|
danielebarchiesi@4
|
968 }
|
danielebarchiesi@4
|
969 }
|
danielebarchiesi@4
|
970 }
|
danielebarchiesi@4
|
971
|
danielebarchiesi@4
|
972 /**
|
danielebarchiesi@4
|
973 * Find a translation for a specific node reference, if it exists.
|
danielebarchiesi@4
|
974 *
|
danielebarchiesi@4
|
975 * @param $reference_node
|
danielebarchiesi@4
|
976 * The untranslated node reference.
|
danielebarchiesi@4
|
977 * @param $langcode
|
danielebarchiesi@4
|
978 *
|
danielebarchiesi@4
|
979 * @return
|
danielebarchiesi@4
|
980 * A nid for the translation of the node reference,
|
danielebarchiesi@4
|
981 * otherwise the original untranslated nid if no translation exists.
|
danielebarchiesi@4
|
982 */
|
danielebarchiesi@4
|
983 function node_reference_find_translation($reference_node, $langcode) {
|
danielebarchiesi@4
|
984 // Check if the source node translation is set and if translations are supported.
|
danielebarchiesi@4
|
985 if (isset($reference_node->tnid) && translation_supported_type($reference_node->type)) {
|
danielebarchiesi@4
|
986 // Determine whether an alternative language is being used.
|
danielebarchiesi@4
|
987 if (!empty($reference_node->language) && $reference_node->language != $langcode) {
|
danielebarchiesi@4
|
988 // Return a corresponding translation nid for the reference (if it exists).
|
danielebarchiesi@4
|
989 $translations = translation_node_get_translations($reference_node->tnid);
|
danielebarchiesi@4
|
990 if (isset($translations[$langcode])) {
|
danielebarchiesi@4
|
991 return $translations[$langcode]->nid;
|
danielebarchiesi@4
|
992 }
|
danielebarchiesi@4
|
993 }
|
danielebarchiesi@4
|
994 }
|
danielebarchiesi@4
|
995 // Return the untranslated reference nid, no matching translations found.
|
danielebarchiesi@4
|
996 return $reference_node->nid;
|
danielebarchiesi@4
|
997 }
|
danielebarchiesi@4
|
998
|
danielebarchiesi@4
|
999 /**
|
danielebarchiesi@4
|
1000 * Implements hook_options_list().
|
danielebarchiesi@4
|
1001 */
|
danielebarchiesi@4
|
1002 function node_reference_options_list($field) {
|
danielebarchiesi@4
|
1003 return _node_reference_options($field, FALSE);
|
danielebarchiesi@4
|
1004 }
|
danielebarchiesi@4
|
1005
|
danielebarchiesi@4
|
1006 /**
|
danielebarchiesi@4
|
1007 * Implements hook_content_migrate_field_alter().
|
danielebarchiesi@4
|
1008 *
|
danielebarchiesi@4
|
1009 * Use this to tweak the conversion of field settings from the D6 style to the
|
danielebarchiesi@4
|
1010 * D7 style for specific situations not handled by basic conversion, as when
|
danielebarchiesi@4
|
1011 * field types or settings are changed.
|
danielebarchiesi@4
|
1012 *
|
danielebarchiesi@4
|
1013 * $field_value['widget_type'] is available to
|
danielebarchiesi@4
|
1014 * see what widget type was originally used.
|
danielebarchiesi@4
|
1015 */
|
danielebarchiesi@4
|
1016 function node_reference_content_migrate_field_alter(&$field_value, $instance_value) {
|
danielebarchiesi@4
|
1017 switch ($field_value['module']) {
|
danielebarchiesi@4
|
1018 case 'nodereference':
|
danielebarchiesi@4
|
1019 $field_value['module'] = 'node_reference';
|
danielebarchiesi@4
|
1020 $field_value['type'] = 'node_reference';
|
danielebarchiesi@4
|
1021
|
danielebarchiesi@4
|
1022 // Translate 'view' settings.
|
danielebarchiesi@4
|
1023 $view_name = isset($field_value['settings']['advanced_view']) ? $field_value['settings']['advanced_view'] : '';
|
danielebarchiesi@4
|
1024 $view_args = isset($field_value['settings']['advanced_view_args']) ? $field_value['settings']['advanced_view_args'] : '';
|
danielebarchiesi@4
|
1025 $view_args = array_map('trim', explode(',', $view_args));
|
danielebarchiesi@4
|
1026 $field_value['settings']['view'] = array(
|
danielebarchiesi@4
|
1027 'view_name' => $view_name,
|
danielebarchiesi@4
|
1028 'display_name' => 'default',
|
danielebarchiesi@4
|
1029 'args' => $view_args,
|
danielebarchiesi@4
|
1030 );
|
danielebarchiesi@4
|
1031 if ($view_name) {
|
danielebarchiesi@4
|
1032 $field_value['messages'][] = t("The field uses the view @view_name to determine referenceable nodes. You will need to manually edit the view and add a display of type 'References'.", array('@view_name' => $view_name));
|
danielebarchiesi@4
|
1033 }
|
danielebarchiesi@4
|
1034 unset($field_value['settings']['advanced_view']);
|
danielebarchiesi@4
|
1035 unset($field_value['settings']['advanced_view_args']);
|
danielebarchiesi@4
|
1036
|
danielebarchiesi@4
|
1037 break;
|
danielebarchiesi@4
|
1038 }
|
danielebarchiesi@4
|
1039 }
|
danielebarchiesi@4
|
1040
|
danielebarchiesi@4
|
1041 /**
|
danielebarchiesi@4
|
1042 * Implements hook_content_migrate_instance_alter().
|
danielebarchiesi@4
|
1043 *
|
danielebarchiesi@4
|
1044 * Use this to tweak the conversion of instance or widget settings from the D6
|
danielebarchiesi@4
|
1045 * style to the D7 style for specific situations not handled by basic
|
danielebarchiesi@4
|
1046 * conversion, as when formatter or widget names or settings are changed.
|
danielebarchiesi@4
|
1047 */
|
danielebarchiesi@4
|
1048 function node_reference_content_migrate_instance_alter(&$instance_value, $field_value) {
|
danielebarchiesi@4
|
1049 switch ($field_value['type']) {
|
danielebarchiesi@4
|
1050 case 'nodereference':
|
danielebarchiesi@4
|
1051 // Massage formatters.
|
danielebarchiesi@4
|
1052 foreach ($instance_value['display'] as $context => &$display) {
|
danielebarchiesi@4
|
1053 switch ($display['type']) {
|
danielebarchiesi@4
|
1054 case 'full':
|
danielebarchiesi@4
|
1055 case 'teaser':
|
danielebarchiesi@4
|
1056 // Those two formatters have been merged into
|
danielebarchiesi@4
|
1057 // 'node_reference_view_mode', with a formatter setting.
|
danielebarchiesi@4
|
1058 $display['type'] = 'node_reference_node';
|
danielebarchiesi@4
|
1059 $display['settings']['node_reference_view_mode'] = $display['type'];
|
danielebarchiesi@4
|
1060 break;
|
danielebarchiesi@4
|
1061
|
danielebarchiesi@4
|
1062 default:
|
danielebarchiesi@4
|
1063 // The formatter names changed, all are prefixed with
|
danielebarchiesi@4
|
1064 // 'node_reference_'.
|
danielebarchiesi@4
|
1065 $display['type'] = 'node_reference_' . $display['type'];
|
danielebarchiesi@4
|
1066 break;
|
danielebarchiesi@4
|
1067 }
|
danielebarchiesi@4
|
1068 }
|
danielebarchiesi@4
|
1069 // Massage the widget.
|
danielebarchiesi@4
|
1070 switch ($instance_value['widget']['type']) {
|
danielebarchiesi@4
|
1071 case 'nodereference_autocomplete':
|
danielebarchiesi@4
|
1072 $instance_value['widget']['type'] = 'node_reference_autocomplete';
|
danielebarchiesi@4
|
1073 $instance_value['widget']['module'] = 'node_reference';
|
danielebarchiesi@4
|
1074 break;
|
danielebarchiesi@4
|
1075 case 'nodereference_select':
|
danielebarchiesi@4
|
1076 $instance_value['widget']['type'] = 'options_select';
|
danielebarchiesi@4
|
1077 $instance_value['widget']['module'] = 'options';
|
danielebarchiesi@4
|
1078 break;
|
danielebarchiesi@4
|
1079 case 'nodereference_buttons':
|
danielebarchiesi@4
|
1080 $instance_value['widget']['type'] = 'options_buttons';
|
danielebarchiesi@4
|
1081 $instance_value['widget']['module'] = 'options';
|
danielebarchiesi@4
|
1082 }
|
danielebarchiesi@4
|
1083 break;
|
danielebarchiesi@4
|
1084 }
|
danielebarchiesi@4
|
1085 }
|
danielebarchiesi@4
|
1086
|
danielebarchiesi@4
|
1087 /**
|
danielebarchiesi@4
|
1088 * Implements hook_field_views_data().
|
danielebarchiesi@4
|
1089 *
|
danielebarchiesi@4
|
1090 * In addition to the default field information we add the relationship for
|
danielebarchiesi@4
|
1091 * views to connect back to the node table.
|
danielebarchiesi@4
|
1092 */
|
danielebarchiesi@4
|
1093 function node_reference_field_views_data($field) {
|
danielebarchiesi@4
|
1094 // No module_load_include(): this hook is invoked from
|
danielebarchiesi@4
|
1095 // views/modules/field.views.inc, which is where that function is defined.
|
danielebarchiesi@4
|
1096 $data = field_views_field_default_views_data($field);
|
danielebarchiesi@4
|
1097
|
danielebarchiesi@4
|
1098 $storage = $field['storage']['details']['sql'];
|
danielebarchiesi@4
|
1099
|
danielebarchiesi@4
|
1100 foreach ($storage as $age => $table_data) {
|
danielebarchiesi@4
|
1101 $table = key($table_data);
|
danielebarchiesi@4
|
1102 $columns = current($table_data);
|
danielebarchiesi@4
|
1103 $id_column = $columns['nid'];
|
danielebarchiesi@4
|
1104 if (isset($data[$table])) {
|
danielebarchiesi@4
|
1105 // Filter: swap the handler to the 'in' operator. The callback receives
|
danielebarchiesi@4
|
1106 // the field name instead of the whole $field structure to keep views
|
danielebarchiesi@4
|
1107 // data to a reasonable size.
|
danielebarchiesi@4
|
1108 $data[$table][$id_column]['filter']['handler'] = 'views_handler_filter_in_operator';
|
danielebarchiesi@4
|
1109 $data[$table][$id_column]['filter']['options callback'] = 'node_reference_views_filter_options';
|
danielebarchiesi@4
|
1110 $data[$table][$id_column]['filter']['options arguments'] = array($field['field_name']);
|
danielebarchiesi@4
|
1111
|
danielebarchiesi@4
|
1112 // Argument: display node.title in argument titles (handled in our custom
|
danielebarchiesi@4
|
1113 // handler) and summary lists (handled by the base views_handler_argument
|
danielebarchiesi@4
|
1114 // handler).
|
danielebarchiesi@4
|
1115 // Both mechanisms rely on the 'name table' and 'name field' information
|
danielebarchiesi@4
|
1116 // below, by joining to a separate copy of the base table from the field
|
danielebarchiesi@4
|
1117 // data table.
|
danielebarchiesi@4
|
1118 $data[$table][$id_column]['argument']['handler'] = 'references_handler_argument';
|
danielebarchiesi@4
|
1119 $data[$table][$id_column]['argument']['name table'] = $table . '_reference';
|
danielebarchiesi@4
|
1120 $data[$table][$id_column]['argument']['name field'] = 'title';
|
danielebarchiesi@4
|
1121 $data[$table . '_reference']['table']['join'][$table] = array(
|
danielebarchiesi@4
|
1122 'left_field' => $id_column,
|
danielebarchiesi@4
|
1123 'table' => 'node',
|
danielebarchiesi@4
|
1124 'field' => 'nid',
|
danielebarchiesi@4
|
1125 );
|
danielebarchiesi@4
|
1126
|
danielebarchiesi@4
|
1127 // Relationship.
|
danielebarchiesi@4
|
1128 $data[$table][$id_column]['relationship'] = array(
|
danielebarchiesi@4
|
1129 'handler' => 'references_handler_relationship',
|
danielebarchiesi@4
|
1130 'base' => 'node',
|
danielebarchiesi@4
|
1131 'base field' => 'nid',
|
danielebarchiesi@4
|
1132 'field' => $id_column,
|
danielebarchiesi@4
|
1133 'label' => $field['field_name'],
|
danielebarchiesi@4
|
1134 'field_name' => $field['field_name'],
|
danielebarchiesi@4
|
1135 );
|
danielebarchiesi@4
|
1136 }
|
danielebarchiesi@4
|
1137 }
|
danielebarchiesi@4
|
1138
|
danielebarchiesi@4
|
1139 return $data;
|
danielebarchiesi@4
|
1140 }
|
danielebarchiesi@4
|
1141
|
danielebarchiesi@4
|
1142 /**
|
danielebarchiesi@4
|
1143 * Implements hook_field_views_data_views_data_alter().
|
danielebarchiesi@4
|
1144 */
|
danielebarchiesi@4
|
1145 function node_reference_field_views_data_views_data_alter(&$data, $field) {
|
danielebarchiesi@4
|
1146 foreach ($field['bundles'] as $entity_type => $bundles) {
|
danielebarchiesi@4
|
1147 $entity_info = entity_get_info($entity_type);
|
danielebarchiesi@4
|
1148 $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
|
danielebarchiesi@4
|
1149
|
danielebarchiesi@4
|
1150 list($label, $all_labels) = field_views_field_label($field['field_name']);
|
danielebarchiesi@4
|
1151 $entity = $entity_info['label'];
|
danielebarchiesi@4
|
1152 if ($entity == t('Node')) {
|
danielebarchiesi@4
|
1153 $entity = t('Content');
|
danielebarchiesi@4
|
1154 }
|
danielebarchiesi@4
|
1155
|
danielebarchiesi@4
|
1156 // Only specify target entity type if the field is used in more than one.
|
danielebarchiesi@4
|
1157 if (count($field['bundles']) > 1) {
|
danielebarchiesi@4
|
1158 $title = t('@field (@field_name) - reverse (to @entity)', array('@entity' => $entity, '@field' => $label, '@field_name' => $field['field_name']));
|
danielebarchiesi@4
|
1159 }
|
danielebarchiesi@4
|
1160 else {
|
danielebarchiesi@4
|
1161 $title = t('@field (@field_name) - reverse', array('@entity' => $entity, '@field' => $label, '@field_name' => $field['field_name']));
|
danielebarchiesi@4
|
1162 }
|
danielebarchiesi@4
|
1163 $data['node'][$pseudo_field_name]['relationship'] = array(
|
danielebarchiesi@4
|
1164 'title' => $title,
|
danielebarchiesi@4
|
1165 'help' => t('Relate each @entity referencing the node through @field.', array('@entity' => $entity, '@field' => $label)),
|
danielebarchiesi@4
|
1166 'handler' => 'views_handler_relationship_entity_reverse',
|
danielebarchiesi@4
|
1167 'field_name' => $field['field_name'],
|
danielebarchiesi@4
|
1168 'field table' => _field_sql_storage_tablename($field),
|
danielebarchiesi@4
|
1169 'field field' => $field['field_name'] . '_nid',
|
danielebarchiesi@4
|
1170 'base' => $entity_info['base table'],
|
danielebarchiesi@4
|
1171 'base field' => $entity_info['entity keys']['id'],
|
danielebarchiesi@4
|
1172 'label' => t('!field_name', array('!field_name' => $field['field_name'])),
|
danielebarchiesi@4
|
1173 );
|
danielebarchiesi@4
|
1174 }
|
danielebarchiesi@4
|
1175 }
|
danielebarchiesi@4
|
1176
|
danielebarchiesi@4
|
1177 /**
|
danielebarchiesi@4
|
1178 * 'options callback' for the views_handler_filter_in_operator filter.
|
danielebarchiesi@4
|
1179 *
|
danielebarchiesi@4
|
1180 * @param $field_name
|
danielebarchiesi@4
|
1181 * The field name.
|
danielebarchiesi@4
|
1182 */
|
danielebarchiesi@4
|
1183 function node_reference_views_filter_options($field_name) {
|
danielebarchiesi@4
|
1184 $options = array();
|
danielebarchiesi@4
|
1185
|
danielebarchiesi@4
|
1186 if ($field = field_info_field($field_name)) {
|
danielebarchiesi@4
|
1187 $options = _node_reference_options($field, TRUE);
|
danielebarchiesi@4
|
1188
|
danielebarchiesi@4
|
1189 // The options are displayed in checkboxes within the filter admin form, and
|
danielebarchiesi@4
|
1190 // in a select within an exposed filter. Checkboxes accept HTML, other
|
danielebarchiesi@4
|
1191 // entities should be encoded; selects require the exact opposite: no HTML,
|
danielebarchiesi@4
|
1192 // no encoding. We go for a middle ground: strip tags, leave entities
|
danielebarchiesi@4
|
1193 // unencoded.
|
danielebarchiesi@4
|
1194 foreach ($options as $key => $value) {
|
danielebarchiesi@4
|
1195 $options[$key] = strip_tags($value);
|
danielebarchiesi@4
|
1196 }
|
danielebarchiesi@4
|
1197 }
|
danielebarchiesi@4
|
1198
|
danielebarchiesi@4
|
1199 return $options;
|
danielebarchiesi@4
|
1200 }
|