Embed an entity within another in Drupal 7

This is some notes of techniques used in a recent project to save time if done again.
The idea was to display multiple related entities within the main entity, node in this case, and to embed the forms for those entities as well.
To keep it neat we will wrap all but the latest entity in a collapsed fieldset.

First of you need to create the entities, I used Entity Construction Kit. For our example let's imagine we created a node of type 'example' and an entity of type and bundle 'embedded_entity'.

To associate the child entity with the parent I used an Entity Reference field on the child that points to the id of the parent and made it required.

The steps we are going to cover:

Finding the related entities

/**
* Helper function to retrieve all entities of a given type that reference the node.
* @param String $type
* @param int $nid
*/
function mymodule_entity_query($type, $nid, $reference_field_id) {
  $query = new EntityFieldQuery;
  $query->entityCondition('entity_type', $type)
     ->fieldCondition($reference_field_id, 'target_id', $nid, '=')
     ->propertyOrderBy('created', 'DESC');

  return $query->execute();
}

Displaying the entities in a collapsable fieldset

/**
* Implementation of hook_node_view().
* You could use hook_entity_view here if not displaying a node.
*/
function mymodule_node_view($node, $view_mode, $langcode) {
  // if we are viewing a full example node.
  if ($node->type == 'example && $view_mode == 'full') {
     // get all embedded_entity entities.
     $result = mymodule_entity_query('embedded_entity',  $node->nid, 'field_myentity_reference');
     if (isset($result['embedded_entity'])) {
       $ids = array_keys($result['embedded_entity']);
       $items = entity_load('embedded_entity', $ids);

       // Generate an array for rendering.
       $entities = entity_view('embedded_entity', $items, 'full');
      
       // Remove the first item as we want it outside the fieldset.
       $first_entity = array_shift($entities);      
       $node->content['entities']['first'] = $first_entity;
      
        // Group the rest in a fieldset.
        $node->content['entities']['fset'] = array(
             '#theme' => 'fieldset',
             '#title' => t('Some title: ') . ' ' . format_date($entity['#entity']->changed),
             '#children'  => render($entities),
             '#attributes' => array(
                'class' => array('collapsible', 'collapsed'),
             ),
              // JS needed to collapse fieldset.
             '#attached' => array(
               'js' => array(
                 'misc/form.js',
                 'misc/collapse.js',
               ),
             ),
           );
       }
   }
}

Displaying the entity add form in the parent
This can be still within hook_node_view().

  module_load_include('inc', 'eck', 'eck.entity');
  $form = eck__entity__add('embedded_entity', 'embedded_entity');
   // Set the required reference field so when we save the entity it is linked to the parent.
  $form['field_myentity_reference'][LANGUAGE_NONE]['#value'] = $node->nid;
 
   $node->content['entity_form'] = array(
      '#theme' => 'fieldset',
      '#title' => 'Add form',
      '#children'  => render($form),
      '#attributes' => array(
        'class' => array('collapsible', 'collapsed'),
      ),
      // JS needed to collapse fieldset.
      '#attached' => array(
        'js' => array(
            'misc/form.js',
            'misc/collapse.js',
        ),
      ),
    );
  

Redirecting the entity back to the parent
This embedded entity has no value on it's own, so we make sure it is displayed in the parent.

/**
* Implementation of hook_entity_info().
*/
function mymodule_entity_info_alter(&$entity_info) {
  // We want to redirect all changes to the embedded entity
  // back to the parent node.
  $entity_info['embedded_entity']['uri callback'] = 'mymodule_entity_redirect';
}

function mymodule_entity_redirect(&$entity) {
  $flow_id = $entity->field_myentity_reference[LANGUAGE_NONE][0]['target_id'];
 
  return array(
    'path' => 'node/' . $flow_id, // path of the parent.
  );
}
/**
* Implementation of hook_form_alter().
**/
function mymodule_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == ''eck__entity__form_add_embedded_entity_embedded_entity') {
    // When the entity form is submitted we want to redirect back to the parent.
    // The embedded form could be submitted via ajax with a little work and this wouldn't be needed.
    $form['#submit'][] = 'mymodule_redirect_submit';
  }
}
/**
* Redirects the embedded entity forms to the node they belong to.
**/
function mymodule_redirect_submit($form, &$form_state) {
  $values = $form_state['values'];
  if ( isset($values['field_myentity_reference'][LANGUAGE_NONE][0]['target_id']) {
    $form_state['redirect'] = 'node/' . $values['field_myentity_reference'][LANGUAGE_NONE][0]['target_id'];
  }
}

I haven't included any theming or hiding fields etc.
Hope you find it useful.

App Stores

PhoneGap2
There has been a lot of talk on HTML5 and how it is just as good as native phone apps. The biggest factor that has been holding it back is getting your HTML5 app found. The web being the wonderful place it is has provided ways to get around that with app stores like openappmkt. On a phone, the default market or store will be the native store of the device. Other App stores won't be found by the majority of users.

There are tools like Apache Cordova originally known as PhoneGap, to package HTML5, CSS and JavaScript into cross platform phone apps. These should be accepted into the itunes app store and Google Play as well as any HTML5 App store, with minimum fuss.

The benefits of using HTML5 Apps should be obvious, smaller development cost and greater device reach. It would be nice if the mobile app stores supported HTML5 without the need for a third party tool to prepackage your app. Hopefully that day will come.

Android Apps for absolute beginners

Android Apps for absolute beginners

Wallace Jackson has authored a book for people with no programming experience, who are interested in developing Android Apps. The book Android Apps for absolute beginners is published by Apress and covers all you need to know to get started in Android development.

The first part of the book looks at getting your development environment set up, using free open source tools such as the eclipse IDE. It goes on to introduce the Android framework before looking at the components of an Android App.

Since the book assumes no prior development experience, it takes you step by step through building an Android App from screen and UI design to handling events, understanding content providers and intents. It seems to be a great book to start your Android development journey.

Drupal Downunder

DrupalDownunder The Drupal Downunder site for the conference in January 2011, is live now. It has been evolving over the last couple of months while we build up to what looks to be a very exciting conference. I'd like to take this opportunity to thank the people involved in organising the conference and website. Special thanks go out to Sheree and Jeff from Marmaladesoul, who I have been working a lot with lately. Chris from Univate and Sean.

HTML5 for iPhone and Android devices

With the opening up and support of API's on mobile devices, HTML5 has the potential to eliminate the need for device specific development.
The w3c has specifications outlining best practices for Mobile Content and Mobile Web Applications
Features like Canvas, SVG, indexedDB and access to Accelerometers, Gyroscope and Cameras will eventually allow web developers to build a HTML5 site that functions like a native App on iPhone, iPad or Android.
The mobile user just needs to visit the site in a browser, bookmark the page and an icon will be added to the desktop, with all necessary data downloaded and stored locally so that it can work again offline. The Apps can be designed to sync with online data sources.

Browser makers are starting to include these features now.

Syndicate content