|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Defines an entity type. |
|
6 */ |
|
7 |
|
8 /** |
|
9 * Implements hook_entity_info(). |
|
10 */ |
|
11 function field_test_entity_info() { |
|
12 // If requested, clear the field cache while this hook is being called. See |
|
13 // testFieldInfoCache(). |
|
14 if (variable_get('field_test_clear_info_cache_in_hook_entity_info', FALSE)) { |
|
15 field_info_cache_clear(); |
|
16 } |
|
17 |
|
18 $bundles = variable_get('field_test_bundles', array('test_bundle' => array('label' => 'Test Bundle'))); |
|
19 $test_entity_modes = array( |
|
20 'full' => array( |
|
21 'label' => t('Full object'), |
|
22 'custom settings' => TRUE, |
|
23 ), |
|
24 'teaser' => array( |
|
25 'label' => t('Teaser'), |
|
26 'custom settings' => TRUE, |
|
27 ), |
|
28 ); |
|
29 |
|
30 return array( |
|
31 'test_entity' => array( |
|
32 'label' => t('Test Entity'), |
|
33 'fieldable' => TRUE, |
|
34 'field cache' => FALSE, |
|
35 'base table' => 'test_entity', |
|
36 'revision table' => 'test_entity_revision', |
|
37 'entity keys' => array( |
|
38 'id' => 'ftid', |
|
39 'revision' => 'ftvid', |
|
40 'bundle' => 'fttype', |
|
41 ), |
|
42 'bundles' => $bundles, |
|
43 'view modes' => $test_entity_modes, |
|
44 ), |
|
45 // This entity type doesn't get form handling for now... |
|
46 'test_cacheable_entity' => array( |
|
47 'label' => t('Test Entity, cacheable'), |
|
48 'fieldable' => TRUE, |
|
49 'field cache' => TRUE, |
|
50 'entity keys' => array( |
|
51 'id' => 'ftid', |
|
52 'revision' => 'ftvid', |
|
53 'bundle' => 'fttype', |
|
54 ), |
|
55 'bundles' => $bundles, |
|
56 'view modes' => $test_entity_modes, |
|
57 ), |
|
58 'test_entity_bundle_key' => array( |
|
59 'label' => t('Test Entity with a bundle key.'), |
|
60 'base table' => 'test_entity_bundle_key', |
|
61 'fieldable' => TRUE, |
|
62 'field cache' => FALSE, |
|
63 'entity keys' => array( |
|
64 'id' => 'ftid', |
|
65 'bundle' => 'fttype', |
|
66 ), |
|
67 'bundles' => array('bundle1' => array('label' => 'Bundle1'), 'bundle2' => array('label' => 'Bundle2')) + $bundles, |
|
68 'view modes' => $test_entity_modes, |
|
69 ), |
|
70 // In this case, the bundle key is not stored in the database. |
|
71 'test_entity_bundle' => array( |
|
72 'label' => t('Test Entity with a specified bundle.'), |
|
73 'base table' => 'test_entity_bundle', |
|
74 'fieldable' => TRUE, |
|
75 'controller class' => 'TestEntityBundleController', |
|
76 'field cache' => FALSE, |
|
77 'entity keys' => array( |
|
78 'id' => 'ftid', |
|
79 'bundle' => 'fttype', |
|
80 ), |
|
81 'bundles' => array('test_entity_2' => array('label' => 'Test entity 2')) + $bundles, |
|
82 'view modes' => $test_entity_modes, |
|
83 ), |
|
84 // @see EntityPropertiesTestCase::testEntityLabel() |
|
85 'test_entity_no_label' => array( |
|
86 'label' => t('Test entity without label'), |
|
87 'fieldable' => TRUE, |
|
88 'field cache' => FALSE, |
|
89 'base table' => 'test_entity', |
|
90 'entity keys' => array( |
|
91 'id' => 'ftid', |
|
92 'revision' => 'ftvid', |
|
93 'bundle' => 'fttype', |
|
94 ), |
|
95 'bundles' => $bundles, |
|
96 'view modes' => $test_entity_modes, |
|
97 ), |
|
98 'test_entity_label' => array( |
|
99 'label' => t('Test entity label'), |
|
100 'fieldable' => TRUE, |
|
101 'field cache' => FALSE, |
|
102 'base table' => 'test_entity', |
|
103 'entity keys' => array( |
|
104 'id' => 'ftid', |
|
105 'revision' => 'ftvid', |
|
106 'bundle' => 'fttype', |
|
107 'label' => 'ftlabel', |
|
108 ), |
|
109 'bundles' => $bundles, |
|
110 'view modes' => $test_entity_modes, |
|
111 ), |
|
112 'test_entity_label_callback' => array( |
|
113 'label' => t('Test entity label callback'), |
|
114 'fieldable' => TRUE, |
|
115 'field cache' => FALSE, |
|
116 'base table' => 'test_entity', |
|
117 'label callback' => 'field_test_entity_label_callback', |
|
118 'entity keys' => array( |
|
119 'id' => 'ftid', |
|
120 'revision' => 'ftvid', |
|
121 'bundle' => 'fttype', |
|
122 ), |
|
123 'bundles' => $bundles, |
|
124 'view modes' => $test_entity_modes, |
|
125 ), |
|
126 ); |
|
127 } |
|
128 |
|
129 /** |
|
130 * Implements hook_entity_info_alter(). |
|
131 */ |
|
132 function field_test_entity_info_alter(&$entity_info) { |
|
133 // Enable/disable field_test as a translation handler. |
|
134 foreach (field_test_entity_info_translatable() as $entity_type => $translatable) { |
|
135 $entity_info[$entity_type]['translation']['field_test'] = $translatable; |
|
136 } |
|
137 // Disable locale as a translation handler. |
|
138 foreach ($entity_info as $entity_type => $info) { |
|
139 $entity_info[$entity_type]['translation']['locale'] = FALSE; |
|
140 } |
|
141 } |
|
142 |
|
143 /** |
|
144 * Helper function to enable entity translations. |
|
145 */ |
|
146 function field_test_entity_info_translatable($entity_type = NULL, $translatable = NULL) { |
|
147 drupal_static_reset('field_has_translation_handler'); |
|
148 $stored_value = &drupal_static(__FUNCTION__, array()); |
|
149 if (isset($entity_type)) { |
|
150 $stored_value[$entity_type] = $translatable; |
|
151 entity_info_cache_clear(); |
|
152 } |
|
153 return $stored_value; |
|
154 } |
|
155 |
|
156 /** |
|
157 * Creates a new bundle for test_entity entities. |
|
158 * |
|
159 * @param $bundle |
|
160 * The machine-readable name of the bundle. |
|
161 * @param $text |
|
162 * The human-readable name of the bundle. If none is provided, the machine |
|
163 * name will be used. |
|
164 */ |
|
165 function field_test_create_bundle($bundle, $text = NULL) { |
|
166 $bundles = variable_get('field_test_bundles', array('test_bundle' => array('label' => 'Test Bundle'))); |
|
167 $bundles += array($bundle => array('label' => $text ? $text : $bundle)); |
|
168 variable_set('field_test_bundles', $bundles); |
|
169 |
|
170 $info = field_test_entity_info(); |
|
171 foreach ($info as $type => $type_info) { |
|
172 field_attach_create_bundle($type, $bundle); |
|
173 } |
|
174 } |
|
175 |
|
176 /** |
|
177 * Renames a bundle for test_entity entities. |
|
178 * |
|
179 * @param $bundle_old |
|
180 * The machine-readable name of the bundle to rename. |
|
181 * @param $bundle_new |
|
182 * The new machine-readable name of the bundle. |
|
183 */ |
|
184 function field_test_rename_bundle($bundle_old, $bundle_new) { |
|
185 $bundles = variable_get('field_test_bundles', array('test_bundle' => array('label' => 'Test Bundle'))); |
|
186 $bundles[$bundle_new] = $bundles[$bundle_old]; |
|
187 unset($bundles[$bundle_old]); |
|
188 variable_set('field_test_bundles', $bundles); |
|
189 |
|
190 $info = field_test_entity_info(); |
|
191 foreach ($info as $type => $type_info) { |
|
192 field_attach_rename_bundle($type, $bundle_old, $bundle_new); |
|
193 } |
|
194 } |
|
195 |
|
196 /** |
|
197 * Deletes a bundle for test_entity objects. |
|
198 * |
|
199 * @param $bundle |
|
200 * The machine-readable name of the bundle to delete. |
|
201 */ |
|
202 function field_test_delete_bundle($bundle) { |
|
203 $bundles = variable_get('field_test_bundles', array('test_bundle' => array('label' => 'Test Bundle'))); |
|
204 unset($bundles[$bundle]); |
|
205 variable_set('field_test_bundles', $bundles); |
|
206 |
|
207 $info = field_test_entity_info(); |
|
208 foreach ($info as $type => $type_info) { |
|
209 field_attach_delete_bundle($type, $bundle); |
|
210 } |
|
211 } |
|
212 |
|
213 /** |
|
214 * Creates a basic test_entity entity. |
|
215 */ |
|
216 function field_test_create_stub_entity($id = 1, $vid = 1, $bundle = 'test_bundle', $label = '') { |
|
217 $entity = new stdClass(); |
|
218 // Only set id and vid properties if they don't come as NULL (creation form). |
|
219 if (isset($id)) { |
|
220 $entity->ftid = $id; |
|
221 } |
|
222 if (isset($vid)) { |
|
223 $entity->ftvid = $vid; |
|
224 } |
|
225 $entity->fttype = $bundle; |
|
226 |
|
227 $label = !empty($label) ? $label : $bundle . ' label'; |
|
228 $entity->ftlabel = $label; |
|
229 |
|
230 return $entity; |
|
231 } |
|
232 |
|
233 /** |
|
234 * Loads a test_entity. |
|
235 * |
|
236 * @param $ftid |
|
237 * The id of the entity to load. |
|
238 * @param $ftvid |
|
239 * (Optional) The revision id of the entity to load. If not specified, the |
|
240 * current revision will be used. |
|
241 * @return |
|
242 * The loaded entity. |
|
243 */ |
|
244 function field_test_entity_test_load($ftid, $ftvid = NULL) { |
|
245 // Load basic strucure. |
|
246 $query = db_select('test_entity', 'fte', array()) |
|
247 ->condition('fte.ftid', $ftid); |
|
248 |
|
249 if ($ftvid) { |
|
250 $query->join('test_entity_revision', 'fter', 'fte.ftid = fter.ftid'); |
|
251 $query->addField('fte', 'ftid'); |
|
252 $query->addField('fte', 'fttype'); |
|
253 $query->addField('fter', 'ftvid'); |
|
254 $query->condition('fter.ftvid', $ftvid); |
|
255 } |
|
256 else { |
|
257 $query->fields('fte'); |
|
258 } |
|
259 |
|
260 $entities = $query->execute()->fetchAllAssoc('ftid'); |
|
261 |
|
262 // Attach fields. |
|
263 if ($ftvid) { |
|
264 field_attach_load_revision('test_entity', $entities); |
|
265 } |
|
266 else { |
|
267 field_attach_load('test_entity', $entities); |
|
268 } |
|
269 |
|
270 return $entities[$ftid]; |
|
271 } |
|
272 |
|
273 /** |
|
274 * Saves a test_entity. |
|
275 * |
|
276 * A new entity is created if $entity->ftid and $entity->is_new are both empty. |
|
277 * A new revision is created if $entity->revision is not empty. |
|
278 * |
|
279 * @param $entity |
|
280 * The entity to save. |
|
281 */ |
|
282 function field_test_entity_save(&$entity) { |
|
283 field_attach_presave('test_entity', $entity); |
|
284 |
|
285 if (!isset($entity->is_new)) { |
|
286 $entity->is_new = empty($entity->ftid); |
|
287 } |
|
288 |
|
289 if (!$entity->is_new && !empty($entity->revision)) { |
|
290 $entity->old_ftvid = $entity->ftvid; |
|
291 unset($entity->ftvid); |
|
292 } |
|
293 |
|
294 $update_entity = TRUE; |
|
295 if ($entity->is_new) { |
|
296 drupal_write_record('test_entity', $entity); |
|
297 drupal_write_record('test_entity_revision', $entity); |
|
298 $op = 'insert'; |
|
299 } |
|
300 else { |
|
301 drupal_write_record('test_entity', $entity, 'ftid'); |
|
302 if (!empty($entity->revision)) { |
|
303 drupal_write_record('test_entity_revision', $entity); |
|
304 } |
|
305 else { |
|
306 drupal_write_record('test_entity_revision', $entity, 'ftvid'); |
|
307 $update_entity = FALSE; |
|
308 } |
|
309 $op = 'update'; |
|
310 } |
|
311 if ($update_entity) { |
|
312 db_update('test_entity') |
|
313 ->fields(array('ftvid' => $entity->ftvid)) |
|
314 ->condition('ftid', $entity->ftid) |
|
315 ->execute(); |
|
316 } |
|
317 |
|
318 // Save fields. |
|
319 $function = "field_attach_$op"; |
|
320 $function('test_entity', $entity); |
|
321 } |
|
322 |
|
323 /** |
|
324 * Menu callback: displays the 'Add new test_entity' form. |
|
325 */ |
|
326 function field_test_entity_add($fttype) { |
|
327 $fttype = str_replace('-', '_', $fttype); |
|
328 $entity = (object)array('fttype' => $fttype); |
|
329 drupal_set_title(t('Create test_entity @bundle', array('@bundle' => $fttype)), PASS_THROUGH); |
|
330 return drupal_get_form('field_test_entity_form', $entity, TRUE); |
|
331 } |
|
332 |
|
333 /** |
|
334 * Menu callback: displays the 'Edit exiisting test_entity' form. |
|
335 */ |
|
336 function field_test_entity_edit($entity) { |
|
337 drupal_set_title(t('test_entity @ftid revision @ftvid', array('@ftid' => $entity->ftid, '@ftvid' => $entity->ftvid)), PASS_THROUGH); |
|
338 return drupal_get_form('field_test_entity_form', $entity); |
|
339 } |
|
340 |
|
341 /** |
|
342 * Test_entity form. |
|
343 */ |
|
344 function field_test_entity_form($form, &$form_state, $entity, $add = FALSE) { |
|
345 // During initial form build, add the entity to the form state for use during |
|
346 // form building and processing. During a rebuild, use what is in the form |
|
347 // state. |
|
348 if (!isset($form_state['test_entity'])) { |
|
349 $form_state['test_entity'] = $entity; |
|
350 } |
|
351 else { |
|
352 $entity = $form_state['test_entity']; |
|
353 } |
|
354 |
|
355 foreach (array('ftid', 'ftvid', 'fttype') as $key) { |
|
356 $form[$key] = array( |
|
357 '#type' => 'value', |
|
358 '#value' => isset($entity->$key) ? $entity->$key : NULL, |
|
359 ); |
|
360 } |
|
361 |
|
362 // Add field widgets. |
|
363 field_attach_form('test_entity', $entity, $form, $form_state); |
|
364 |
|
365 if (!$add) { |
|
366 $form['revision'] = array( |
|
367 '#access' => user_access('administer field_test content'), |
|
368 '#type' => 'checkbox', |
|
369 '#title' => t('Create new revision'), |
|
370 '#default_value' => FALSE, |
|
371 '#weight' => 100, |
|
372 ); |
|
373 } |
|
374 $form['submit'] = array( |
|
375 '#type' => 'submit', |
|
376 '#value' => t('Save'), |
|
377 '#weight' => 101, |
|
378 ); |
|
379 |
|
380 return $form; |
|
381 } |
|
382 |
|
383 /** |
|
384 * Validate handler for field_test_entity_form(). |
|
385 */ |
|
386 function field_test_entity_form_validate($form, &$form_state) { |
|
387 entity_form_field_validate('test_entity', $form, $form_state); |
|
388 } |
|
389 |
|
390 /** |
|
391 * Submit handler for field_test_entity_form(). |
|
392 */ |
|
393 function field_test_entity_form_submit($form, &$form_state) { |
|
394 $entity = field_test_entity_form_submit_build_test_entity($form, $form_state); |
|
395 $insert = empty($entity->ftid); |
|
396 field_test_entity_save($entity); |
|
397 |
|
398 $message = $insert ? t('test_entity @id has been created.', array('@id' => $entity->ftid)) : t('test_entity @id has been updated.', array('@id' => $entity->ftid)); |
|
399 drupal_set_message($message); |
|
400 |
|
401 if ($entity->ftid) { |
|
402 $form_state['redirect'] = 'test-entity/manage/' . $entity->ftid . '/edit'; |
|
403 } |
|
404 else { |
|
405 // Error on save. |
|
406 drupal_set_message(t('The entity could not be saved.'), 'error'); |
|
407 $form_state['rebuild'] = TRUE; |
|
408 } |
|
409 } |
|
410 |
|
411 /** |
|
412 * Updates the form state's entity by processing this submission's values. |
|
413 */ |
|
414 function field_test_entity_form_submit_build_test_entity($form, &$form_state) { |
|
415 $entity = $form_state['test_entity']; |
|
416 entity_form_submit_build_entity('test_entity', $entity, $form, $form_state); |
|
417 return $entity; |
|
418 } |
|
419 |
|
420 /** |
|
421 * Form combining two separate entities. |
|
422 */ |
|
423 function field_test_entity_nested_form($form, &$form_state, $entity_1, $entity_2) { |
|
424 // First entity. |
|
425 foreach (array('ftid', 'ftvid', 'fttype') as $key) { |
|
426 $form[$key] = array( |
|
427 '#type' => 'value', |
|
428 '#value' => $entity_1->$key, |
|
429 ); |
|
430 } |
|
431 field_attach_form('test_entity', $entity_1, $form, $form_state); |
|
432 |
|
433 // Second entity. |
|
434 $form['entity_2'] = array( |
|
435 '#type' => 'fieldset', |
|
436 '#title' => t('Second entity'), |
|
437 '#tree' => TRUE, |
|
438 '#parents' => array('entity_2'), |
|
439 '#weight' => 50, |
|
440 ); |
|
441 foreach (array('ftid', 'ftvid', 'fttype') as $key) { |
|
442 $form['entity_2'][$key] = array( |
|
443 '#type' => 'value', |
|
444 '#value' => $entity_2->$key, |
|
445 ); |
|
446 } |
|
447 field_attach_form('test_entity', $entity_2, $form['entity_2'], $form_state); |
|
448 |
|
449 $form['save'] = array( |
|
450 '#type' => 'submit', |
|
451 '#value' => t('Save'), |
|
452 '#weight' => 100, |
|
453 ); |
|
454 |
|
455 return $form; |
|
456 } |
|
457 |
|
458 /** |
|
459 * Validate handler for field_test_entity_nested_form(). |
|
460 */ |
|
461 function field_test_entity_nested_form_validate($form, &$form_state) { |
|
462 $entity_1 = (object) $form_state['values']; |
|
463 field_attach_form_validate('test_entity', $entity_1, $form, $form_state); |
|
464 |
|
465 $entity_2 = (object) $form_state['values']['entity_2']; |
|
466 field_attach_form_validate('test_entity', $entity_2, $form['entity_2'], $form_state); |
|
467 } |
|
468 |
|
469 /** |
|
470 * Submit handler for field_test_entity_nested_form(). |
|
471 */ |
|
472 function field_test_entity_nested_form_submit($form, &$form_state) { |
|
473 $entity_1 = (object) $form_state['values']; |
|
474 field_attach_submit('test_entity', $entity_1, $form, $form_state); |
|
475 field_test_entity_save($entity_1); |
|
476 |
|
477 $entity_2 = (object) $form_state['values']['entity_2']; |
|
478 field_attach_submit('test_entity', $entity_2, $form['entity_2'], $form_state); |
|
479 field_test_entity_save($entity_2); |
|
480 |
|
481 drupal_set_message(t('test_entities @id_1 and @id_2 have been updated.', array('@id_1' => $entity_1->ftid, '@id_2' => $entity_2->ftid))); |
|
482 } |
|
483 |
|
484 /** |
|
485 * Controller class for the test_entity_bundle entity type. |
|
486 * |
|
487 * This extends the DrupalDefaultEntityController class, adding required |
|
488 * special handling for bundles (since they are not stored in the database). |
|
489 */ |
|
490 class TestEntityBundleController extends DrupalDefaultEntityController { |
|
491 |
|
492 protected function attachLoad(&$entities, $revision_id = FALSE) { |
|
493 // Add bundle information. |
|
494 foreach ($entities as $key => $entity) { |
|
495 $entity->fttype = 'test_entity_bundle'; |
|
496 $entities[$key] = $entity; |
|
497 } |
|
498 parent::attachLoad($entities, $revision_id); |
|
499 } |
|
500 } |