From 9279e84593445ab84990a187e7b4ec5ff8831477 Mon Sep 17 00:00:00 2001
From: Claudiu Cristea <clau.cristea@gmail.com>
Date: Tue, 15 Nov 2011 11:17:11 +0200
Subject: [PATCH] Issue #1340878 by claudiu.cristea: Added Extend Profile2.


diff --git a/sites/all/modules/profile2/contrib/profile2_og_access.info b/sites/all/modules/profile2/contrib/profile2_og_access.info
deleted file mode 100644
index 7d16267..0000000
--- a/sites/all/modules/profile2/contrib/profile2_og_access.info
+++ /dev/null
@@ -1,6 +0,0 @@
-name = Profile2 group access
-description = Adds Organic groups permissions to control profile access on the group level.
-core = 7.x
-dependencies[] = profile2
-dependencies[] = og
-package = "Organic groups"
\ No newline at end of file
diff --git a/sites/all/modules/profile2/contrib/profile2_og_access.module b/sites/all/modules/profile2/contrib/profile2_og_access.module
deleted file mode 100644
index a8a5275..0000000
--- a/sites/all/modules/profile2/contrib/profile2_og_access.module
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-/**
- * @file
- * Profile2 og access integration module.
- */
-
-/**
- * Implements hook_og_permission().
- */
-function profile2_og_access_og_permission() {
-  $permissions = array();
-  // Generate per profile type permissions.
-  foreach (profile2_get_types() as $type) {
-    $type_name = check_plain($type->type);
-    $permissions += array(
-      "edit any $type_name profile" => array(
-        'title' => t('%type_name: Edit any profile', array('%type_name' => $type->label)),
-      ),
-      "view any $type_name profile" => array(
-        'title' => t('%type_name: View any profile', array('%type_name' => $type->label)),
-      ),
-    );
-  }
-  return $permissions;
-}
-
-/**
- * Implements hook_profile2_access().
- *
- * @see profile2_profile2_access()
- */
-function profile2_og_access_profile2_access($op, $profile = NULL, $account = NULL) {
-  if (isset($profile) && ($type_name = $profile->type) && $profile->identifier() && $op != 'delete') {
-    // Only return TRUE if og grants access. So other modules may still grant
-    // access in case og does not.
-    if (og_user_access_entity("$op any $type_name profile", 'profile2', $profile, $account)) {
-      return TRUE;
-    }
-  }
-}
\ No newline at end of file
diff --git a/sites/all/modules/profile2/contrib/profile2_og_access/profile2_og_access.info b/sites/all/modules/profile2/contrib/profile2_og_access/profile2_og_access.info
new file mode 100644
index 0000000..7d16267
--- /dev/null
+++ b/sites/all/modules/profile2/contrib/profile2_og_access/profile2_og_access.info
@@ -0,0 +1,6 @@
+name = Profile2 group access
+description = Adds Organic groups permissions to control profile access on the group level.
+core = 7.x
+dependencies[] = profile2
+dependencies[] = og
+package = "Organic groups"
\ No newline at end of file
diff --git a/sites/all/modules/profile2/contrib/profile2_og_access/profile2_og_access.module b/sites/all/modules/profile2/contrib/profile2_og_access/profile2_og_access.module
new file mode 100644
index 0000000..a8a5275
--- /dev/null
+++ b/sites/all/modules/profile2/contrib/profile2_og_access/profile2_og_access.module
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Profile2 og access integration module.
+ */
+
+/**
+ * Implements hook_og_permission().
+ */
+function profile2_og_access_og_permission() {
+  $permissions = array();
+  // Generate per profile type permissions.
+  foreach (profile2_get_types() as $type) {
+    $type_name = check_plain($type->type);
+    $permissions += array(
+      "edit any $type_name profile" => array(
+        'title' => t('%type_name: Edit any profile', array('%type_name' => $type->label)),
+      ),
+      "view any $type_name profile" => array(
+        'title' => t('%type_name: View any profile', array('%type_name' => $type->label)),
+      ),
+    );
+  }
+  return $permissions;
+}
+
+/**
+ * Implements hook_profile2_access().
+ *
+ * @see profile2_profile2_access()
+ */
+function profile2_og_access_profile2_access($op, $profile = NULL, $account = NULL) {
+  if (isset($profile) && ($type_name = $profile->type) && $profile->identifier() && $op != 'delete') {
+    // Only return TRUE if og grants access. So other modules may still grant
+    // access in case og does not.
+    if (og_user_access_entity("$op any $type_name profile", 'profile2', $profile, $account)) {
+      return TRUE;
+    }
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/profile2/contrib/profile2_page.inc b/sites/all/modules/profile2/contrib/profile2_page.inc
deleted file mode 100644
index f3bb8b5..0000000
--- a/sites/all/modules/profile2/contrib/profile2_page.inc
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-
-/**
- * @file
- * Adds separate pages for viewing and editing profiles.
- */
-
-/**
- * Shows the profile page for the current user.
- *
- * @see user_page()
- */
-function profile2_page_own($base_path) {
-  global $user;
-  if ($user->uid) {
-    menu_set_active_item($base_path . '/' . $user->uid);
-    return menu_execute_active_handler(NULL, FALSE);
-  }
-  else {
-    return drupal_get_form('user_login');
-  }
-}
-
-/**
- * Profile view page.
- */
-function profile2_page_view($profile) {
-  drupal_set_title($profile->label());
-  return $profile->view('page');
-}
-
-/**
- * The profile edit form.
- */
-function profile2_form($form, &$form_state, $profile) {
-  if (empty($form_state['profiles'])) {
-    $form_state['profiles'][$profile->type] = $profile;
-  }
-  // Prevent invoking the same hooks twice, so tell profile2_attach_form() to
-  // skip invoking the hooks.
-  $form_state['profile2_skip_hook'] = TRUE;
-  profile2_attach_form($form, $form_state);
-
-  $form['actions'] = array('#type' => 'actions');
-  $form['actions']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-    '#weight' => 40,
-  );
-  if (empty($profile->is_new) && user_access('administer profiles')) {
-    $form['actions']['delete'] = array(
-      '#type' => 'submit',
-      '#value' => t('Delete profile'),
-      '#weight' => 45,
-      '#limit_validation_errors' => array(),
-      '#submit' => array('profile2_form_submit_delete')
-    );
-  }
-  $form['#submit'][] = 'profile2_form_submit';
-  return $form;
-}
-
-/**
- * Profile form submit handler.
- */
-function profile2_form_submit($form, &$form_state) {
-  // The profile is being saved by profile2_form_submit_handler().
-  drupal_set_message(t('The changes have been saved.'));
-  $form_state['redirect'] = $form_state['profile2']->path();
-}
-
-/**
- * Profile form submit handler for the delete button.
- */
-function profile2_form_submit_delete($form, &$form_state) {
-  $form_state['redirect'] = $form_state['profile2']->path() . '/delete';
-}
-
-/**
- * Confirm form for deleting a profile.
- */
-function profile2_page_delete_confirm_form($form, &$form_state, $profile) {
-  $form_state += array('profile2' => $profile);
-  $confirm_question = t('Are you sure you want to delete profile %label?', array('%label' => $profile->label));
-  return confirm_form($form, $confirm_question, $profile->path());
-}
-
-function profile2_page_delete_confirm_form_submit($form, &$form_state) {
-  $profile = $form_state['profile2'];
-  $profile->delete();
-  drupal_set_message(t('Deleted %label.', array('%label' => $profile->label)));
-  $form_state['redirect'] = 'user/' . $profile->uid;
-}
diff --git a/sites/all/modules/profile2/contrib/profile2_page.info b/sites/all/modules/profile2/contrib/profile2_page.info
deleted file mode 100644
index 9bbe466..0000000
--- a/sites/all/modules/profile2/contrib/profile2_page.info
+++ /dev/null
@@ -1,4 +0,0 @@
-name = Profile2 pages
-description = Adds separate pages for viewing and editing profiles.
-core = 7.x
-dependencies[] = profile2
\ No newline at end of file
diff --git a/sites/all/modules/profile2/contrib/profile2_page.module b/sites/all/modules/profile2/contrib/profile2_page.module
deleted file mode 100644
index 7c930fb..0000000
--- a/sites/all/modules/profile2/contrib/profile2_page.module
+++ /dev/null
@@ -1,195 +0,0 @@
-<?php
-
-/**
- * @file
- * Adds separate pages for viewing and editing profiles.
- */
-
-/**
- * Implements hook_menu().
- */
-function profile2_page_menu() {
-  $items = array();
-
-  // Bugfix for uninstalling the module, see http://drupal.org/node/1008346.
-  if (!module_exists('profile2')) {
-    return;
-  }
-
-  foreach (profile2_get_types() as $type_name => $type) {
-    if (!empty($type->data['use_page'])) {
-      $path = profile2_page_get_base_path($type);
-      $count = count(explode('/', $path));
-
-      $items[$path] = array(
-        'title callback' => 'profile2_page_own_title',
-        'title arguments' => array($type_name),
-        'page callback' => 'profile2_page_own',
-        'page arguments' => array($path),
-        'access callback' => 'user_access',
-        'access arguments' => array("edit own $type_name profile"),
-        'file' => 'profile2_page.inc',
-        'menu_name' => 'user-menu',
-      );
-
-      $items[$path . '/%profile2_by_uid'] = array(
-        'page callback' => 'profile2_page_view',
-        'page arguments' => array($count),
-        'load arguments' => array($type_name),
-        'access callback' => 'profile2_access',
-        'access arguments' => array('view', $count),
-        'file' => 'profile2_page.inc',
-      );
-      $items[$path . '/%profile2_by_uid/view'] = array(
-        'title' => 'View',
-        'type' => MENU_DEFAULT_LOCAL_TASK,
-        'load arguments' => array($type_name),
-        'weight' => -10,
-      );
-      $items[$path . '/%profile2_by_uid/edit'] = array(
-        'page callback' => 'entity_ui_get_form',
-        'page arguments' => array('profile2', $count),
-        'load arguments' => array($type_name),
-        'access callback' => 'profile2_access',
-        'access arguments' => array('edit', $count),
-        'title' => 'Edit',
-        'type' => MENU_LOCAL_TASK,
-        'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
-        'file' => 'profile2_page.inc',
-      );
-      $items[$path . '/%profile2_by_uid/delete'] = array(
-        'page callback' => 'drupal_get_form',
-        'page arguments' => array('profile2_page_delete_confirm_form', $count),
-        'load arguments' => array($type_name),
-        'access callback' => 'profile2_access',
-        'access arguments' => array('delete', $count),
-        'title' => 'Delete',
-        'type' => MENU_LOCAL_TASK,
-        'context' => MENU_CONTEXT_INLINE,
-        'file' => 'profile2_page.inc',
-      );
-    }
-  }
-  return $items;
-}
-
-/**
- * Menu load callback.
- *
- * Returns the profile object for the given user. If there is none yet, a new
- * object is created.
- */
-function profile2_by_uid_load($uid, $type_name) {
-  if ($uid && is_numeric($uid) && ($account = user_load($uid))) {
-    $profile = profile2_load_by_user($account, $type_name);
-    if (!$profile) {
-      $profile = profile_create(array('type' => $type_name));
-      $profile->setUser($account);
-      $profile->is_new = TRUE;
-    }
-    return $profile;
-  }
-  return FALSE;
-}
-
-/**
- * Returns the base path to use as profile page.
- */
-function profile2_page_get_base_path($profile_type) {
-  // Allow for an easy customization of the page's base path.
-  if (!empty($profile_type->data['page_path'])) {
-    return $profile_type->data['page_path'];
-  }
-  return 'profile-' . $profile_type->type;
-}
-
-/**
- * Implements hook_forms().
- */
-function profile2_page_forms($form_id, $args) {
-  // For efficiency, only act if the third argument is 'profile2'.
-  if (isset($args[2]) && is_string($args[2]) && $args[2] == 'profile2') {
-    $info = entity_get_info('profile2');
-    // Translate bundle form ids to the base form id 'profile2_form'.
-    foreach ($info['bundles'] as $bundle => $bundle_info) {
-      $forms['profile2_edit_' . $bundle . '_form']['callback'] = 'profile2_form';
-      $forms['profile2_edit_' . $bundle . '_form']['wrapper callback'] = 'entity_ui_form_defaults';
-    }
-    return $forms;
-  }
-}
-
-/**
- * Implements hook_profile2_type_load().
- */
-function profile2_page_profile2_type_load($types) {
-  foreach ($types as $type) {
-    if (!empty($type->data['use_page'])) {
-      // Disable user categories and the user account view.
-      $type->userCategory = FALSE;
-      $type->userView = FALSE;
-    }
-  }
-}
-
-/**
- * Implements hook_entity_info_alter().
- */
-function profile2_page_entity_info_alter(&$entity_info) {
-  // Add new view modes for the page.
-  $entity_info['profile2']['view modes']['page'] = array(
-    'label' => t('Profile page'),
-     'custom settings' => FALSE,
-  );
-  $entity_info['profile2']['view modes']['teaser'] = array(
-    'label' => t('Teaser'),
-    'custom settings' => FALSE,
-  );
-  $entity_info['profile2']['uri callback'] = 'profile2_page_uri_callback';
-  $entity_info['profile2']['form callback'] = 'profile2_page_form_callback';
-}
-
-/**
- * URI callback pointing to the profile page.
- *
- * @see profile2_pages_entity_info_alter()
- */
-function profile2_page_uri_callback($profile) {
-  $type = $profile->type();
-  if (!empty($type->data['use_page'])) {
-    return array('path' => profile2_page_get_base_path($type) . '/' . $profile->uid);
-  }
-  // Fall back to the default callback.
-  return $profile->defaultUri();
-}
-
-/**
- * Form callback for entity_form().
- */
-function profile2_page_form_callback($profile) {
-  // Pre-populate the form-state with the right form include.
-  form_load_include($form_state, 'inc', 'profile2_page');
-  return entity_ui_get_form('profile2', $profile, 'edit', $form_state);
-}
-
-/**
- * Menu title callback.
- */
-function profile2_page_own_title($type_name) {
-  $type = profile2_get_types($type_name);
-  return user_is_logged_in() ? t('My @profile-label', array('@profile-label' => drupal_strtolower($type->label))) : check_plain($type->label);
-}
-
-/**
- * Implements hook_form_FORM_ID_alter() for the profile2 type form..
- */
-function profile2_page_form_profile2_type_form_alter(&$form, &$form_state) {
-  $type = $form_state['profile2_type'];
-  $form['data']['use_page'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Provide a separate page for editing profiles.'),
-    '#description' => t('If enabled, a separate menu item for editing the profile is generated and the profile is hidden from the user account page.'),
-    '#default_value' => !empty($type->is_new) || !empty($type->data['use_page']),
-  );
-  $form['data']['#tree'] = TRUE;
-}
diff --git a/sites/all/modules/profile2/contrib/profile2_user/profile2_page.inc b/sites/all/modules/profile2/contrib/profile2_user/profile2_page.inc
new file mode 100644
index 0000000..ac39121
--- /dev/null
+++ b/sites/all/modules/profile2/contrib/profile2_user/profile2_page.inc
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * @file
+ * Adds separate pages for viewing and editing profiles.
+ */
+
+/**
+ * Shows the profile page for the current user.
+ *
+ * @see user_page()
+ */
+function profile2_page_own($base_path) {
+  global $user;
+  if ($user->uid) {
+    menu_set_active_item($base_path . '/' . $user->uid);
+    return menu_execute_active_handler(NULL, FALSE);
+  }
+  else {
+    return drupal_get_form('user_login');
+  }
+}
+
+/**
+ * Profile view page.
+ */
+function profile2_page_view($profile) {
+  drupal_set_title($profile->label());
+  return $profile->view('page');
+}
+
+/**
+ * The profile edit form.
+ */
+function profile2_form($form, &$form_state, $profile) {
+  if (empty($form_state['profiles'])) {
+    $form_state['profiles'][$profile->type] = $profile;
+  }
+  // Prevent invoking the same hooks twice, so tell profile2_attach_form() to
+  // skip invoking the hooks.
+  $form_state['profile2_skip_hook'] = TRUE;
+  profile2_attach_form($form, $form_state);
+
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+    '#weight' => 40,
+  );
+  if (!empty($profile->pid) && user_access('administer profiles')) {
+    $form['actions']['delete'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete profile'),
+      '#weight' => 45,
+      '#limit_validation_errors' => array(),
+      '#submit' => array('profile2_form_submit_delete')
+    );
+  }
+  $form['#submit'][] = 'profile2_form_submit';
+  return $form;
+}
+
+/**
+ * Profile form submit handler.
+ */
+function profile2_form_submit($form, &$form_state) {
+  // The profile is being saved by profile2_form_submit_handler().
+  drupal_set_message(t('The changes have been saved.'));
+  $form_state['redirect'] = $form_state['profile2']->path();
+}
+
+/**
+ * Profile form submit handler for the delete button.
+ */
+function profile2_form_submit_delete($form, &$form_state) {
+  $form_state['redirect'] = $form_state['profile2']->path() . '/delete';
+}
+
+/**
+ * Confirm form for deleting a profile.
+ */
+function profile2_page_delete_confirm_form($form, &$form_state, $profile) {
+  $form_state += array('profile2' => $profile);
+  $confirm_question = t('Are you sure you want to delete profile %label?', array('%label' => $profile->label));
+  return confirm_form($form, $confirm_question, $profile->path());
+}
+
+function profile2_page_delete_confirm_form_submit($form, &$form_state) {
+  $profile = $form_state['profile2'];
+  $profile->delete();
+  drupal_set_message(t('Deleted %label.', array('%label' => $profile->label)));
+  $form_state['redirect'] = 'user/' . $profile->entity_id;
+}
diff --git a/sites/all/modules/profile2/contrib/profile2_user/profile2_page.info b/sites/all/modules/profile2/contrib/profile2_user/profile2_page.info
new file mode 100644
index 0000000..47dedff
--- /dev/null
+++ b/sites/all/modules/profile2/contrib/profile2_user/profile2_page.info
@@ -0,0 +1,4 @@
+name = Profile2 pages
+description = Adds separate pages for viewing and editing profiles.
+core = 7.x
+dependencies[] = profile2_user
diff --git a/sites/all/modules/profile2/contrib/profile2_user/profile2_page.module b/sites/all/modules/profile2/contrib/profile2_user/profile2_page.module
new file mode 100644
index 0000000..50c1ab6
--- /dev/null
+++ b/sites/all/modules/profile2/contrib/profile2_user/profile2_page.module
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * @file
+ * Adds separate pages for viewing and editing profiles.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function profile2_page_menu() {
+  $items = array();
+
+  // Bugfix for uninstalling the module, see http://drupal.org/node/1008346.
+  if (!module_exists('profile2')) {
+    return;
+  }
+
+  foreach (profile2_get_types() as $type_name => $profile_type) {
+    if (in_array('user', $profile_type->entity) && !empty($profile_type->data['user']['page'])) {
+      $path = profile2_page_get_base_path($profile_type);
+      $count = count(explode('/', $path));
+
+      $items[$path] = array(
+        'title callback' => 'profile2_page_own_title',
+        'title arguments' => array($type_name),
+        'page callback' => 'profile2_page_own',
+        'page arguments' => array($path),
+        'access callback' => 'user_access',
+        'access arguments' => array("edit own $type_name profile"),
+        'file' => 'profile2_page.inc',
+        'menu_name' => 'user-menu',
+      );
+
+      $items[$path . '/%profile2_user_by_uid'] = array(
+        'page callback' => 'profile2_page_view',
+        'page arguments' => array($count),
+        'load arguments' => array($type_name),
+        'access callback' => 'profile2_access',
+        'access arguments' => array('view', $count),
+        'file' => 'profile2_page.inc',
+      );
+      $items[$path . '/%profile2_user_by_uid/view'] = array(
+        'title' => 'View',
+        'type' => MENU_DEFAULT_LOCAL_TASK,
+        'load arguments' => array($type_name),
+        'weight' => -10,
+      );
+      $items[$path . '/%profile2_user_by_uid/edit'] = array(
+        'page callback' => 'entity_ui_get_form',
+        'page arguments' => array('profile2', $count),
+        'load arguments' => array($type_name),
+        'access callback' => 'profile2_access',
+        'access arguments' => array('edit', $count),
+        'title' => 'Edit',
+        'type' => MENU_LOCAL_TASK,
+        'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+        'file' => 'profile2_page.inc',
+      );
+      $items[$path . '/%profile2_user_by_uid/delete'] = array(
+        'page callback' => 'drupal_get_form',
+        'page arguments' => array('profile2_page_delete_confirm_form', $count),
+        'load arguments' => array($type_name),
+        'access callback' => 'profile2_access',
+        'access arguments' => array('delete', $count),
+        'title' => 'Delete',
+        'type' => MENU_LOCAL_TASK,
+        'context' => MENU_CONTEXT_INLINE,
+        'file' => 'profile2_page.inc',
+      );
+    }
+  }
+  return $items;
+}
+
+/**
+ * Returns the base path to use as profile page.
+ */
+function profile2_page_get_base_path($profile_type) {
+  // Allow for an easy customization of the page's base path.
+  if (!empty($profile_type->data['page_path'])) {
+    return $profile_type->data['page_path'];
+  }
+  return 'profile-' . $profile_type->type;
+}
+
+/**
+ * Implements hook_forms().
+ */
+function profile2_page_forms($form_id, $args) {
+  // For efficiency, only act if the third argument is 'profile2'.
+  if (isset($args[2]) && is_string($args[2]) && $args[2] == 'profile2') {
+    $info = entity_get_info('profile2');
+    // Translate bundle form ids to the base form id 'profile2_form'.
+    foreach ($info['bundles'] as $bundle => $bundle_info) {
+      $forms['profile2_edit_' . $bundle . '_form']['callback'] = 'profile2_form';
+      $forms['profile2_edit_' . $bundle . '_form']['wrapper callback'] = 'entity_ui_form_defaults';
+    }
+    return $forms;
+  }
+}
+
+/**
+ * Implements hook_entity_info_alter().
+ */
+function profile2_page_entity_info_alter(&$entity_info) {
+  // Add new view modes for the page.
+  $entity_info['profile2']['view modes']['page'] = array(
+    'label' => t('Profile page'),
+    'custom settings' => FALSE,
+  );
+  $entity_info['profile2']['view modes']['teaser'] = array(
+    'label' => t('Teaser'),
+    'custom settings' => FALSE,
+  );
+  $entity_info['profile2']['form callback'] = 'profile2_page_form_callback';
+}
+
+/**
+ * Implements hook_profile2_uri_callback_alter().
+ *
+ * @see hook_profile2_uri_callback_alter()
+ * @see profile2_uri_callback_alter()
+ * @see profile2_user_uri_callback()
+ * @see url()
+ */
+function profile2_page_profile2_uri_callback_alter(&$uri, $profile) {
+  if ($profile->entity_type != 'user') {
+    return;
+  }
+  $profile_type = $profile->type();
+  $path = profile2_page_get_base_path($profile_type);
+
+  // Alter only if we are on profile page and page view is allowed.
+  if (arg(0) == $path && !empty($profile_type->data['user']['page'])) {
+    $uri =  array('path' => profile2_page_get_base_path($profile_type)  . (isset($profile->entity_id) ? '/' . $profile->entity_id : ''));
+  }
+}
+
+/**
+ * Form callback for entity_form().
+ */
+function profile2_page_form_callback($profile) {
+  // Pre-populate the form-state with the right form include.
+  form_load_include($form_state, 'inc', 'profile2_page');
+  return entity_ui_get_form('profile2', $profile, 'edit', $form_state);
+}
+
+/**
+ * Menu title callback.
+ */
+function profile2_page_own_title($type_name) {
+  $type = profile2_get_types($type_name);
+  return user_is_logged_in() ? t('My @profile-label', array('@profile-label' => drupal_strtolower($type->label))) : check_plain($type->label);
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for the profile2 type form..
+ */
+function profile2_page_form_profile2_type_form_alter(&$form, &$form_state) {
+  $type = $form_state['profile2_type'];
+  $form['data']['user']['page'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Provide a separate page for editing profiles'),
+    '#description' => t('If enabled, a separate menu item for editing the profile is generated.'),
+    '#default_value' => !empty($type->data['user']['page']),
+  );
+}
diff --git a/sites/all/modules/profile2/contrib/profile2_user/profile2_user.info b/sites/all/modules/profile2/contrib/profile2_user/profile2_user.info
new file mode 100644
index 0000000..0adb4b4
--- /dev/null
+++ b/sites/all/modules/profile2/contrib/profile2_user/profile2_user.info
@@ -0,0 +1,5 @@
+name = Profile2 User
+description = Adds support for user entity.
+core = 7.x
+dependencies[] = profile2
+files[] = profile2_user.test
diff --git a/sites/all/modules/profile2/contrib/profile2_user/profile2_user.install b/sites/all/modules/profile2/contrib/profile2_user/profile2_user.install
new file mode 100644
index 0000000..8935f1e
--- /dev/null
+++ b/sites/all/modules/profile2/contrib/profile2_user/profile2_user.install
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the Profile2 User module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function profile2_user_install() {
+  // Add an initial user profile type, but only if installed manually. In case
+  // the module is installed via an installation profile, skip that.
+  if (!drupal_installation_attempted() && !($profile_type = profile2_type_load('main'))) {
+    $type = entity_create('profile2_type',
+      array(
+        'type' => 'main',
+        'label' => t('Main profile'),
+        'entity' => array('user'),
+        'weight' => 0,
+        'data' => array(
+          'user' => array(
+            'registration' => TRUE,
+            'category' => TRUE,
+            'view' => TRUE,
+            'page' => TRUE
+          ),
+        ),
+      )
+    );
+    $type->save();
+    user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('edit own main profile', 'view own main profile'));
+    drupal_set_message(t('A main profile type has been created and assigned to all users. Go to the <a href="!url">Profile types</a> page to add some fields or to configure further profile types.', array('!url' => url('admin/structure/profiles'))));
+  }
+}
diff --git a/sites/all/modules/profile2/contrib/profile2_user/profile2_user.module b/sites/all/modules/profile2/contrib/profile2_user/profile2_user.module
new file mode 100644
index 0000000..c428cb8
--- /dev/null
+++ b/sites/all/modules/profile2/contrib/profile2_user/profile2_user.module
@@ -0,0 +1,365 @@
+<?php
+
+/**
+ * @file
+ * Adds support for user entity.
+ */
+
+/**
+ * Implements hook_profile2_info().
+ *
+ * This is the first thing a module should implement in order to attach profiles
+ * to an arbitrary entity.
+ */
+function profile2_user_profile2_info() {
+  return array(
+    'user' => array(
+      'uri callback' => 'profile2_user_uri_callback',
+      'settings form' => 'profile2_user_settings_form',
+    ),
+  );
+}
+
+/**
+ * Implements hook_profile2_uri_callback().
+ *
+ * @see profile2_uri_callback()
+ */
+function profile2_user_uri_callback($profile) {
+  return array(
+    'path' => 'user' . (isset($profile->entity_id) ? '/' . $profile->entity_id : ''),
+    'options' => array('fragment' => 'profile-' . $profile->type),
+  );
+}
+
+/**
+ * Implements hook_entity_info_alter().
+ */
+function profile2_user_entity_info_alter(&$entity_info) {
+  // Add new view modes for account.
+  $entity_info['profile2']['view modes']['account'] = array(
+    'label' => t('User account'),
+    'custom settings' => FALSE,
+  );
+}
+
+/**
+ * Fetch profiles by account.
+ *
+ * @param $account
+ *   The user account to load profiles for, or its uid.
+ * @param $type_name
+ *   To load a single profile, pass the type name of the profile to load.
+ * @return
+ *   Either a single profile or an array of profiles keyed by profile type.
+ *
+ * @see profile2_load_multiple()
+ * @see profile2_profile2_delete()
+ * @see Profile::save()
+ */
+function profile2_user_load_by_user($account, $type_name = NULL) {
+  // Use a separate query to determine all profile ids per user and cache them.
+  // That way we can look up profiles by id and benefit from the static cache
+  // of the entity loader.
+  $cache = &drupal_static(__FUNCTION__, array());
+  $uid = is_object($account) ? $account->uid : $account;
+
+  if (!isset($cache[$uid])) {
+    if (empty($type_name)) {
+      $profiles = profile2_load_multiple(FALSE, array('entity_type' => 'user', 'entity_id' => $uid));
+      // Cache ids for further lookups.
+      $cache[$uid] = array();
+      foreach ($profiles as $pid => $profile) {
+        $cache[$uid][$profile->type] = $pid;
+      }
+      return $profiles ? array_combine(array_keys($cache[$uid]), $profiles) : array();
+    }
+    $cache[$uid] = db_select('profile', 'p')
+      ->fields('p', array('type', 'pid'))
+      ->condition('p.entity_type', 'user')
+      ->condition('p.entity_id', $uid)
+      ->execute()
+      ->fetchAllKeyed();
+  }
+  if (isset($type_name)) {
+    return isset($cache[$uid][$type_name]) ? profile2_load($cache[$uid][$type_name]) : FALSE;
+  }
+  // Return an array containing profiles keyed by profile type.
+  return $cache[$uid] ? array_combine(array_keys($cache[$uid]), profile2_load_multiple($cache[$uid])) : $cache[$uid];
+}
+
+/**
+ * Implements hook_profile2_update().
+ */
+function profile2_user_profile2_update(Profile $profile) {
+  if ($profile->entity_type == 'user') {
+    // Update the static cache from profile2_user_load_by_user().
+    $cache = &drupal_static('profile2_user_load_by_user', array());
+    if (isset($cache[$profile->entity_id])) {
+      $cache[$profile->entity_id][$profile->type] = $profile->pid;
+    }
+  }
+}
+
+/**
+ * Implements hook_profile2_delete().
+ */
+function profile2_user_profile2_delete($profile) {
+  // Clear the static cache from profile2_user_load_by_user().
+  $cache = &drupal_static('profile2_user_load_by_user', array());
+  unset($cache[$profile->entity_id][$profile->type]);
+}
+
+/**
+ * Implements hook_user_delete().
+ */
+function profile2_user_user_delete($account) {
+  foreach (profile2_user_load_by_user($account) as $profile) {
+    profile2_delete($profile);
+  }
+}
+
+/**
+ * Implements hook_user_categories().
+ */
+function profile2_user_user_categories() {
+  $data = array();
+  foreach (profile2_get_types() as $type => $profile_type) {
+    if (in_array('user', $profile_type->entity) && $profile_type->data['user']['category']) {
+      $data[] = array(
+        'name' => $type,
+        'title' => $profile_type->label,
+        // Add an offset so a weight of 0 appears right of the account category.
+        'weight' => $profile_type->weight + 3,
+        'access callback' => 'profile2_user_category_access',
+        'access arguments' => array(1, $profile_type)
+      );
+    }
+  }
+  return $data;
+}
+
+/**
+ * Implements hook_user_view().
+ */
+function profile2_user_user_view($account, $view_mode, $langcode) {
+  foreach (profile2_get_types() as $type => $profile_type) {
+    if ($profile_type->data['user']['view'] && ($profile = profile2_user_load_by_user($account, $type))) {
+      if (profile2_access('view', $profile)) {
+        $account->content['profile_' . $type] = array(
+          '#type' => 'user_profile_category',
+          '#title' => $profile->label,
+          '#prefix' => '<a id="profile-' . $profile->type . '"></a>',
+        );
+        $account->content['profile_' . $type]['view'] = $profile->view('page');
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for the user edit form.
+ *
+ * @see profile2_form_validate_handler
+ * @see profile2_form_submit_handler
+ */
+function profile2_user_form_user_profile_form_alter(&$form, &$form_state) {
+  if (($type = profile2_get_types($form['#user_category'])) && in_array('user', $type->entity) && $type->data['user']['category']) {
+    if (empty($form_state['profiles'])) {
+      $profile = profile2_user_load_by_user($form['#user'], $form['#user_category']);
+      if (empty($profile)) {
+        $profile = profile2_create(array('type' => $form['#user_category'], 'entity_type' => 'user', 'entity_id' => $form['#user']->uid));
+      }
+      $form_state['profiles'][$profile->type] = $profile;
+    }
+    profile2_attach_form($form, $form_state);
+  }
+}
+
+/**
+ * Form settings callback for profile type form.
+ */
+function profile2_user_settings_form(&$form_state) {
+  $form['registration'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Show during user account registration'),
+    '#description' => t('If checked, this profile type will be displayed in a fieldset inside the user account registration form.'),
+    '#default_value' => !empty($form_state['profile2_type']->data['user']['registration']),
+  );
+  $form['category'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Profile editable in user categories'),
+    '#description' => t('If checked, this profile can be edited in user categories, under <code>user/[UID]/edit/[PROFILE_TYPE]</code>.'),
+    '#default_value' => !empty($form_state['profile2_type']->data['user']['category']),
+  );
+  $form['view'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Display on user account page'),
+    '#description' => t('If checked, this profile type will be dispalyed on the user account page.'),
+    '#default_value' => !empty($form_state['profile2_type']->data['user']['view']),
+  );
+  return $form;
+}
+
+/**
+ * Attempt to load a profile type by user ID.
+ *
+ * Returns the profile object for the given user. If there is none yet, a new
+ * object is created.
+ *
+ * @param $uid
+ *   Integer with the user ID.
+ * @param $type_name
+ *   String with the type name.
+ *
+ * @return
+ *   A Profile object.
+ */
+function profile2_user_by_uid_load($uid, $type_name) {
+  if ($uid && is_numeric($uid) && ($account = user_load($uid))) {
+    $profile = profile2_user_load_by_user($account, $type_name);
+    if (!$profile) {
+      $profile = profile2_create(array('type' => $type_name, 'entity_type' => 'user', 'entity_id' => $uid));
+    }
+    return $profile;
+  }
+  return FALSE;
+}
+
+/**
+ * Menu item access callback - check if a user has access to a profile category.
+ */
+function profile2_user_category_access($account, $profile_type) {
+  // As there might be no profile yet, create a new object for being able to run
+  // a proper access check.
+  $profile = profile2_create(array('type' => $profile_type->type, 'entity_type' => 'user', 'entity_id' => $account->uid));
+  return (($account->uid > 0) && $profile_type->data['user']['category'] && profile2_access('edit', $profile, $account));
+}
+
+/**
+ * Implements hook_profile2_access().
+ *
+ * @see hook_profile2_access()
+ * @see profile2_access()
+ */
+function profile2_user_profile2_access($op, $profile = NULL, $account = NULL) {
+
+  // Don't grant access for users to delete their profile.
+  if (isset($profile) && ($profile->entity_type == 'user') && ($type_name = $profile->type) && $op != 'delete') {
+    if (user_access("$op any $type_name profile", $account)) {
+      return TRUE;
+    }
+    $account = isset($account) ? $account : $GLOBALS['user'];
+    if (isset($profile->entity_id) && $profile->entity_id == $account->uid && user_access("$op own $type_name profile", $account)) {
+      return TRUE;
+    }
+  }
+  // Do not explicitly deny access so others may still grant access.
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for the registration form.
+ */
+function profile2_user_form_user_register_form_alter(&$form, &$form_state) {
+  foreach (profile2_get_types() as $type_name => $profile_type) {
+    if (!empty($profile_type->data['user']['registration']) && in_array('user', $profile_type->entity)) {
+      if (empty($form_state['profiles'][$type_name])) {
+        $form_state['profiles'][$type_name] = profile2_create(array('type' => $type_name, 'entity_type' => 'user'));
+      }
+      profile2_attach_form($form, $form_state);
+      // Wrap each profile form in a fieldset.
+      $form['profile_' . $type_name] += array(
+        '#type' => 'fieldset',
+        '#title' => check_plain($profile_type->label),
+      );
+    }
+  }
+}
+
+/**
+ * Implements hook_profile2_submit_profile_alter().
+ *
+ * During registration phase set the uid field of the newly created user to the
+ * profile Profile object.
+ *
+ * @see hook_profile2_submitted_profile_alter()
+ * @see profile2_form_submit_handler()
+ * @see drupal_alter()
+ */
+function profile2_user_profile2_submitted_profile_alter(&$profile, $form_state) {
+  if (empty($profile->entity_id) && $profile->entity_type == 'user' && isset($form_state['user']->uid)) {
+    $profile->entity_id = $form_state['user']->uid;
+  }
+}
+
+/**
+ * Submit handler that builds and saves all profiles in the form.
+ *
+ * @see profile2_attach_form()
+ */
+function profile2_user_form_submit_handler(&$form, &$form_state) {
+  foreach ($form_state['profiles'] as $type => $profile) {
+    // During registration set the uid field of the newly created user.
+    if (empty($profile->entity_id) && isset($form_state['user']->uid)) {
+      $form_state['profiles'][$type]->entity_id = $form_state['user']->uid;
+    }
+  }
+}
+
+/**
+ * Entity metadata callback to load profiles for the given user account.
+ */
+function profile2_user_get_properties($account, array $options, $name) {
+  // Remove the leading 'profile_' from the property name to get the type name.
+  $profile = profile2_user_load_by_user($account, substr($name, 8));
+  return $profile ? $profile : NULL;
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Adds a checkbox for controlling field view access to fields added to
+ * profiles.
+ */
+function profile2_user_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
+
+  // Load the Profile2 profile type.
+  $profile_type = profile2_get_types($form['instance']['bundle']['#value']);
+  //  Check if this type is attached to user entity.
+  if (!in_array('user', $profile_type->entity)) {
+    return;
+  }
+
+  if ($form['instance']['entity_type']['#value'] == 'profile2') {
+    $form['field']['settings']['profile2_private'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Make the content of this field private.'),
+      '#default_value' => !empty($form['#field']['settings']['profile2_private']),
+      '#description' => t('This setting is used only in User profiles. If checked, the content of this field is only shown to the profile owner and administrators.'),
+    );
+  }
+  else {
+    // Add the value to the form so it isn't lost.
+    $form['field']['settings']['profile2_private'] = array(
+      '#type' => 'value',
+      '#value' => !empty($form['#field']['settings']['profile2_private']),
+    );
+  }
+}
+
+/**
+ * Implements hook_field_access().
+ */
+function profile2_user_field_access($op, $field, $entity_type, $profile = NULL, $account = NULL) {
+  if (!user_access('administer profiles', $account) && $entity_type == 'profile2' && $profile->entity_type == 'user' && $op == 'view' && !empty($field['settings']['profile2_private'])) {
+    // For profiles, deny general view access for private fields.
+    if (!isset($profile)) {
+      return FALSE;
+    }
+    // Also deny view access, if someone else views a private field.
+    $account = isset($account) ? $account : $GLOBALS['user'];
+    if ($account->uid != $profile->entity_id) {
+      return FALSE;
+    }
+  }
+}
diff --git a/sites/all/modules/profile2/contrib/profile2_user/profile2_user.test b/sites/all/modules/profile2/contrib/profile2_user/profile2_user.test
new file mode 100644
index 0000000..8da92c3
--- /dev/null
+++ b/sites/all/modules/profile2/contrib/profile2_user/profile2_user.test
@@ -0,0 +1,138 @@
+<?php
+
+/**
+ * Test basic CRUD functionality.
+ */
+class ProfileUserCRUDTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Editing user profiles',
+      'description' => 'Tests basic CRUD and editing of user profiles.',
+      'group' => 'Profile2',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('profile2', 'profile2_user', 'locale');
+
+    profile2_type_save(new ProfileType(array(
+      'type' => 'test',
+      'label' => 'label',
+      'entity' => array('user'),
+      'weight' => 0
+    )));
+    profile2_type_save(new ProfileType(array(
+      'type' => 'test2',
+      'label' => 'label2',
+      'entity' => array('user'),
+      'weight' => 2
+    )));
+    profile2_load_multiple(FALSE, array(), TRUE);
+
+    // Add a field to main type, which is created during module installation.
+    $field = array(
+      'field_name' => 'profile_fullname',
+      'type' => 'text',
+      'cardinality' => 1,
+      'translatable' => FALSE,
+    );
+    field_create_field($field);
+    $instance = array(
+      'entity_type' => 'profile2',
+      'field_name' => 'profile_fullname',
+      'bundle' => 'main',
+      'label' => 'Full name',
+      'description' => 'Specify your first and last name.',
+      'widget' => array(
+        'type' => 'text_textfield',
+        'weight' => 0,
+      ),
+    );
+    field_create_instance($instance);
+  }
+
+  /**
+   * Tests CRUD for a profile related to a user and one unrelated to a user.
+   */
+  function testCRUD() {
+    $user1 = $this->drupalCreateUser();
+    // Create profiles for the user1 and unrelated to a user.
+    profile2_save(profile2_create(array('type' => 'test', 'entity_type' => 'user', 'entity_id' => $user1->uid)));
+    profile2_save(profile2_create(array('type' => 'test2', 'entity_type' => 'user', 'entity_id' => $user1->uid)));
+    $profile = profile2_create(array('type' => 'test', 'entity_type' => 'user', 'entity_id' => NULL));
+    profile2_save($profile);
+
+    $profiles = profile2_user_load_by_user($user1);
+    $this->assertEqual($profiles['test']->label(), 'label', 'Created and loaded profile 1.');
+    $this->assertEqual($profiles['test2']->label(), 'label2', 'Created and loaded profile 2.');
+
+    // Test looking up from static cache works also.
+    $profiles = profile2_user_load_by_user($user1);
+    $this->assertEqual($profiles['test']->label, 'label', 'Looked up profiles again.');
+
+    $loaded = profile2_load($profile->pid);
+    $this->assertEqual($loaded->pid, $profile->pid, 'Loaded profile unrelated to a user.');
+
+    profile2_delete($profiles['test']);
+    $profiles2 = profile2_user_load_by_user($user1);
+    $this->assertEqual(array_keys($profiles2), array('test2'), 'Profile successfully deleted.');
+
+    profile2_save($profiles2['test2']);
+    $this->assertEqual($profiles['test2']->pid, $profiles2['test2']->pid, 'Profile successfully updated.');
+
+    // Delete a profile type.
+    profile2_type_delete(profile2_get_types('test'));
+    // Try deleting multiple profiles by deleting all existing profiles.
+    $pids = array_keys(profile2_load_multiple(FALSE));
+    profile2_delete_multiple($pids);
+  }
+
+  /**
+   * Test registration integration.
+   */
+  function testRegistrationIntegration() {
+    // Allow registration by site visitors without administrator approval.
+    variable_set('user_register', 1);
+    $edit = array();
+    $edit['name'] = $name = $this->randomName();
+    $edit['mail'] = $mail = $edit['name'] . '@example.com';
+    $edit['profile_main[profile_fullname][und][0][value]'] = $this->randomName();
+    $this->drupalPost('user/register', $edit, t('Create new account'));
+    $this->assertText(t('A welcome message with further instructions has been sent to your e-mail address.'), t('User registered successfully.'));
+    $return = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
+    $new_user = reset($return);
+    $this->assertTrue($new_user->status, t('New account is active after registration.'));
+    $this->assertEqual(profile2_user_load_by_user($new_user, 'main')->profile_fullname[LANGUAGE_NONE][0]['value'], $edit['profile_main[profile_fullname][und][0][value]'], 'Profile created.');
+  }
+
+  /**
+   * Test basic edit and display.
+   */
+  function testEditAndDisplay() {
+    user_role_revoke_permissions(DRUPAL_AUTHENTICATED_RID, array('edit own main profile', 'view own main profile'));
+    $user1 = $this->drupalCreateUser();
+    $this->drupalLogin($user1);
+    // Make sure access is denied to the profile.
+    $this->drupalGet('user/' . $user1->uid . '/edit/main');
+    $this->assertText(t('Access denied'), 'Access has been denied.');
+
+    // Test creating a profile manually (e.g. by an admin) and ensure the user
+    // may not see it.
+    profile2_create(array('type' => 'main', 'entity_type' => 'user', 'entity_id' => $user1->uid))->save();
+    $this->drupalGet('user/' . $user1->uid);
+    $this->assertNoText(t('Main profile'), 'Profile data is not visible to the owner.');
+
+    $user2 = $this->drupalCreateUser(array('edit own main profile', 'view own main profile'));
+    $this->drupalLogin($user2);
+
+    // Create profiles for the user2.
+    $edit['profile_main[profile_fullname][und][0][value]'] = $this->randomName();
+    $this->drupalPost('user/' . $user2->uid . '/edit/main', $edit, t('Save'));
+    $this->assertText(t('The changes have been saved.'), 'Profile saved.');
+    $this->assertEqual(profile2_user_load_by_user($user2, 'main')->profile_fullname[LANGUAGE_NONE][0]['value'], $edit['profile_main[profile_fullname][und][0][value]'], 'Profile edited.');
+
+    $this->drupalGet('user/' . $user2->uid);
+    $this->assertText(check_plain($edit['profile_main[profile_fullname][und][0][value]']), 'Profile displayed.');
+  }
+}
diff --git a/sites/all/modules/profile2/profile2.admin.inc b/sites/all/modules/profile2/profile2.admin.inc
index 4394dc0..0b98719 100644
--- a/sites/all/modules/profile2/profile2.admin.inc
+++ b/sites/all/modules/profile2/profile2.admin.inc
@@ -25,6 +25,15 @@ class Profile2TypeUIController extends EntityDefaultUIController {
  */
 function profile2_type_form($form, &$form_state, $profile_type, $op = 'edit') {
 
+  // Build the list of entities that are allowed to have profile2 attached.
+  if (!($entities = module_invoke_all('profile2_info'))) {
+    $form['message'] = array(
+      '#type' => 'markup',
+      '#markup' => t('There are no modules providing entities for attaching Profile2 profiles. You must enable first at least one module like <em>Profile2 User</em> to be able to create profiles. Developers may define such entities by implementing <code>hook_profile2_info()</code>.'),
+    );
+    return $form;
+  }
+
   if ($op == 'clone') {
     $profile_type->label .= ' (cloned)';
     $profile_type->type = '';
@@ -51,13 +60,55 @@ function profile2_type_form($form, &$form_state, $profile_type, $op = 'edit') {
     '#description' => t('A unique machine-readable name for this profile type. It must only contain lowercase letters, numbers, and underscores.'),
   );
 
-  $form['data']['#tree'] = TRUE;
-  $form['data']['registration'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Show during user account registration.'),
-    '#default_value' => !empty($profile_type->data['registration']),
+  $form['entity'] = array(
+    '#tree' => TRUE,
+    '#type' => 'fieldset',
+    '#title' => t('Entities'),
+    '#description' => t('Entities where this Profile2 profile type is attached.'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+
+  $form['data'] = array(
+    '#tree' => TRUE,
+    '#type' => 'fieldset',
+    '#title' => t('Settings'),
+    '#description' => t('Various settings for each entity wher this Profile2 profile type is attached.'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
   );
 
+  $entity_info =& entity_get_info();
+  foreach ($entities as $entity_type => $entity_data) {
+    $entity_label = $entity_info[$entity_type]['label'];
+    $title = format_string('@label [@name]', array('@label' => $entity_label, '@name' => $entity_type));
+    $description = $entity_info[$entity_type]['description'];
+
+    $form['entity'][$entity_type] = array(
+      '#type' => 'checkbox',
+      '#title' => $title,
+      '#description' => $description,
+      '#default_value' => (isset($profile_type->entity)  && in_array($entity_type, $profile_type->entity)) ? $entity_type : FALSE,
+      '#return_value' => $entity_type,
+    );
+
+    // See if the module has implemented settings and expose them in the form.
+    if (isset($entity_data['settings form']) && function_exists($function = $entity_data['settings form']) && is_array($module_form = $function($form_state))) {
+      $form['data'][$entity_type] = array(
+        '#type' => 'fieldset',
+        '#title' => $entity_label,
+        '#states' => array(
+          'visible' => array(
+            ':input[name="entity[' . $entity_type . ']"]' => array('checked' => TRUE),
+          ),
+        ),
+        '#collapsible' => TRUE,
+        '#collapsed' => FALSE,
+      );
+      $form['data'][$entity_type] += $module_form;
+    }
+  }
+
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['submit'] = array(
     '#type' => 'submit',
@@ -78,9 +129,22 @@ function profile2_type_form($form, &$form_state, $profile_type, $op = 'edit') {
 }
 
 /**
+ * Form API validation callback for the type form.
+ */
+function profile2_type_form_validate(&$form, &$form_state) {
+  if (!array_filter($form_state['values']['entity'])) {
+    form_set_error('entity', t('You must select at least one entity where this profile type will be attached.'));
+  }
+}
+
+/**
  * Form API submit callback for the type form.
  */
 function profile2_type_form_submit(&$form, &$form_state) {
+
+  // Make entity array clean.
+  $form_state['values']['entity'] = array_values(array_filter($form_state['values']['entity']));
+
   $profile_type = entity_ui_form_submit_build_entity($form, $form_state);
   // Save and go back.
   $profile_type->save();
diff --git a/sites/all/modules/profile2/profile2.api.php b/sites/all/modules/profile2/profile2.api.php
index 02cdffb..73cf438 100644
--- a/sites/all/modules/profile2/profile2.api.php
+++ b/sites/all/modules/profile2/profile2.api.php
@@ -13,6 +13,51 @@
  */
 
 /**
+ * Define entities where profile2 profiles may be attached.
+ *
+ * @return array
+ *   Return an associative array having entity types as keys and values as
+ *   associative arrays with next keys:
+ *   - uri callback: Each entity should define its own URI callback.
+ *   - settings form: Each entity may contribute with settings to the profile
+ *     type form. This value is a function callback which has to return a FAPI
+ *     associative array.
+ */
+function hook_profile2_info() {
+  return array(
+    'user' => array(
+      'uri callback' => 'profile2_user_uri_callback',
+      'settings form' => 'profile2_user_settings_form'
+    ),
+    'node' => array(
+      'uri callback' => 'profile2_node_uri',
+      'settings form' => 'mymodule_settings'
+    ),
+  );
+}
+
+/**
+ * Allow entity URI alteration.
+ *
+ * Modules may implement this hook to alter the Profile entity URI.
+ *
+ * @param $uri
+ *   An URI associative array passed by reference with next keys:
+ *   - 'path': A Drupal path.
+ *   - 'options': An associative array having keys and values as url() function.
+ * @param $profile
+ *   A Profile entity object.
+ *
+ * @see url()
+ * @see hook_profile2_uri_callback()
+ * @see profile2_uri_callback()
+ * @see profile2_page_profile2_uri_callback()
+ */
+function hook_profile2_uri_callback_alter($uri, $profile) {
+  $uri['options']['absolute'] = TRUE;
+}
+
+/**
 * Act on profiles being loaded from the database.
 *
 * This hook is invoked during profile loading, which is handled by
@@ -159,8 +204,7 @@ function hook_profile2_view_alter($build) {
  */
 function hook_profile2_type_load($types) {
   if (isset($types['main'])) {
-    $types['main']->userCategory = FALSE;
-    $types['main']->userView = FALSE;
+    $types['main']->flag = 'foo';
   }
 }
 
@@ -309,5 +353,22 @@ function hook_profile2_access($op, $profile = NULL, $account = NULL) {
 }
 
 /**
+ * Alters a submitted profile.
+ *
+ * Alters a profile that has been submitted through FAPI just before the profile
+ * is passed to profile2_save().
+ *
+ * @param $profile
+ *   The profile to be altered passed by reference as am Profile object.
+ * @param $form_state
+ *   The FAPI form state associative array.
+ *
+ * @see profile2_user_profile2_submitted_profile_alter().
+ */
+function hook_profile2_submitted_profile_alter(&$profile, &$form_state) {
+  $profile->foo = 'bar';
+}
+
+/**
  * @}
  */
diff --git a/sites/all/modules/profile2/profile2.info b/sites/all/modules/profile2/profile2.info
index df64223..8a56a53 100644
--- a/sites/all/modules/profile2/profile2.info
+++ b/sites/all/modules/profile2/profile2.info
@@ -3,6 +3,5 @@ description = Supports configurable user profiles.
 core = 7.x
 files[] = profile2.admin.inc
 files[] = profile2.info.inc
-files[] = profile2.test
 dependencies[] = entity
 configure = admin/structure/profiles
\ No newline at end of file
diff --git a/sites/all/modules/profile2/profile2.install b/sites/all/modules/profile2/profile2.install
index 918cfba..f5c510f 100644
--- a/sites/all/modules/profile2/profile2.install
+++ b/sites/all/modules/profile2/profile2.install
@@ -6,25 +6,6 @@
  */
 
 /**
- * Implements hook_install().
- */
-function profile2_install() {
-  // Add an initial profile type, but only if installed manually. In case the
-  // module is installed via an installation profile, skip that.
-  if (!drupal_installation_attempted()) {
-    $type = entity_create('profile2_type', array(
-      'type' => 'main',
-      'label' => t('Main profile'),
-      'weight' => 0,
-      'data' => array('registration' => TRUE, 'use_page' => TRUE),
-    ));
-    $type->save();
-    user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('edit own main profile', 'view own main profile'));
-    drupal_set_message(t('A main profile type has been created and assigned to all users. Go to the <a href="!url">Profile types</a> page to add some fields or to configure further profile types.', array('!url' => url('admin/structure/profiles'))));
-  }
-}
-
-/**
  * Implements hook_schema().
  */
 function profile2_schema() {
@@ -43,22 +24,27 @@ function profile2_schema() {
         'not null' => TRUE,
         'default' => '',
       ),
-      'uid' => array(
+      'entity_type' => array(
+        'description' => 'The entity type this data is attached to.',
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+      ),
+      'entity_id' => array(
         'type' => 'int',
         'unsigned' => TRUE,
-        'not null' => FALSE,
-        'default' => NULL,
-        'description' => "The {users}.uid of the associated user.",
+        'not null' => TRUE,
+        'description' => "The entity id this data is attached to.",
       ),
     ),
     'indexes' => array(
-      'uid' => array('uid'),
+      'entity_id' => array('entity_id'),
+      'entity_type' => array('entity_type'),
+    ),
+    'unique keys' => array(
+      'instance' => array('type', 'entity_type', 'entity_id'),
     ),
     'foreign keys' => array(
-      'uid' => array(
-        'table' => 'users',
-        'columns' => array('uid' => 'uid'),
-      ),
       'type' => array(
         'table' => 'profile_type',
         'columns' => array('type' => 'type'),
@@ -108,6 +94,33 @@ function profile2_schema() {
       'type' => array('type'),
     ),
   );
+
+  $schema['profile_type_entity'] = array(
+    'description' => 'Stores relations between profile types and entities.',
+    'fields' => array(
+      'type' => array(
+        'description' => 'The {profile_type}.type of this profile.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'entity_type' => array(
+        'description' => 'The entity type this data is attached to.',
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('type', 'entity_type'),
+    'foreign keys' => array(
+      'type' => array(
+        'table' => 'profile_type',
+        'columns' => array('type' => 'type'),
+      ),
+    ),
+  );
+
   return $schema;
 }
 
@@ -129,3 +142,100 @@ function profile2_update_7100() {
     'not null' => FALSE,
   ));
 }
+
+/**
+ * Extend profile2 to other entities than "user".
+ */
+function profile2_update_7101() {
+  // Drop keys first.
+  db_drop_index('profile', 'uid');
+
+  // Change "uid" to "entity_id".
+  db_change_field('profile', 'uid', 'entity_id',
+    array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'description' => "The entity id this data is attached to.",
+    ),
+    array(
+      'indexes' => array(
+        'entity_id' => array('entity_id'),
+      ),
+    )
+  );
+
+  // Add the "entity_type" field.
+  db_add_field('profile', 'entity_type',
+    array(
+      'description' => 'The entity type this data is attached to.',
+      'type' => 'varchar',
+      'length' => 128,
+      'not null' => TRUE,
+      'initial' => 'user',
+    ),
+    array(
+      'indexes' => array(
+        'entity_type' => array('entity_type'),
+      ),
+    )
+  );
+
+  // Add uniqueness constrain.
+  db_add_unique_key('profile', 'instance', array('type', 'entity_type', 'entity_id'));
+
+  // Create the new "profile_type" <=> "entity" relation table.
+  db_create_table('profile_type_entity',
+    array(
+      'description' => 'Stores relations between profile types and entities.',
+      'fields' => array(
+        'type' => array(
+          'description' => 'The {profile_type}.type of this profile.',
+          'type' => 'varchar',
+          'length' => 32,
+          'not null' => TRUE,
+          'default' => '',
+        ),
+        'entity_type' => array(
+          'description' => 'The entity type this data is attached to.',
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+        ),
+      ),
+      'primary key' => array('type', 'entity_type'),
+      'foreign keys' => array(
+        'type' => array(
+          'table' => 'profile_type',
+          'columns' => array('type' => 'type'),
+        ),
+      ),
+    )
+  );
+
+  // Convert Profile2 profile type data.
+  foreach (db_query("SELECT id, type, data FROM {profile_type}")->fetchAll() as $profile_type) {
+    $data = unserialize($profile_type->data);
+    $data['user']['registration'] = !empty($data['registration']);
+    $use_page = !empty($data['use_page']);
+    $data['user']['page'] = $use_page;
+    $data['user']['category'] = $data['user']['view'] = !$use_page;
+    unset($data['registration'], $data['use_page']);
+
+    // We cannot use drupal_write_record() here.
+    db_update('profile_type')
+      ->fields(array('data' => serialize($data)))
+      ->condition('id', $profile_type->id)
+      ->execute();
+
+    db_insert('profile_type_entity')
+      ->fields(array('type' => $profile_type->type, 'entity_type' => 'user'))
+      ->execute();
+  }
+
+  // Enable the new Profile2 User (profile2_user).
+  module_enable(array('profile2_user'));
+
+  // Rebuilds module data because some modules changed their location.
+  system_rebuild_module_data();
+}
diff --git a/sites/all/modules/profile2/profile2.module b/sites/all/modules/profile2/profile2.module
index d57a3c5..d913eed 100644
--- a/sites/all/modules/profile2/profile2.module
+++ b/sites/all/modules/profile2/profile2.module
@@ -13,17 +13,12 @@ function profile2_entity_info() {
     'profile2' => array(
       'label' => t('Profile'),
       'plural label' => t('Profiles'),
-      'description' => t('Profile2 user profiles.'),
+      'description' => t('Profile2 profiles.'),
       'entity class' => 'Profile',
       'controller class' => 'EntityAPIController',
       'base table' => 'profile',
       'fieldable' => TRUE,
-      'view modes' => array(
-        'account' => array(
-          'label' => t('User account'),
-          'custom settings' => FALSE,
-        ),
-      ),
+      'view modes' => array(),
       'entity keys' => array(
         'id' => 'pid',
         'bundle' => 'type',
@@ -33,7 +28,7 @@ function profile2_entity_info() {
         'bundle' => 'type',
       ),
       'label callback' => 'entity_class_label',
-      'uri callback' => 'entity_class_uri',
+      'uri callback' => 'profile2_uri_callback',
       'access callback' => 'profile2_access',
       'module' => 'profile2',
       'metadata controller class' => 'Profile2MetadataController'
@@ -67,9 +62,9 @@ function profile2_entity_info() {
   $return['profile2_type'] = array(
     'label' => t('Profile type'),
     'plural label' => t('Profile types'),
-    'description' => t('Profiles types of Profile2 user profiles.'),
+    'description' => t('Profiles types of Profile2 profiles.'),
     'entity class' => 'ProfileType',
-    'controller class' => 'EntityAPIControllerExportable',
+    'controller class' => 'ProfileType2ControllerExportable',
     'base table' => 'profile_type',
     'fieldable' => FALSE,
     'bundle of' => 'profile2',
@@ -93,6 +88,33 @@ function profile2_entity_info() {
 }
 
 /**
+ * URI callback for Profile2 entities.
+ *
+ * @param $profile
+ *   The Profile profile object.
+ *
+ * @return
+ *   An associative array having  next keys:
+ *   - 'path': The URI to be passed as first argument to url() function.
+ *   - 'options': Same as url() second argument.
+ *
+ * @see url()
+ * @see profile2_user_profile2_uri_callback()
+ */
+function profile2_uri_callback($profile) {
+  $supported_entities = module_invoke_all('profile2_info');
+  $function = isset($supported_entities[$profile->entity_type]['uri callback']) ? $supported_entities[$profile->entity_type]['uri callback'] : NULL;
+
+  // Call the entity type specific URI handler.
+  $uri = (!is_null($function) && function_exists($function)) ? $function($profile) : array();
+
+  // Allow URI alteration.
+  drupal_alter('profile2_uri_callback', $uri, $profile);
+
+  return $uri;
+}
+
+/**
  * Menu argument loader; Load a profile type by string.
  *
  * @param $type
@@ -111,11 +133,11 @@ function profile2_permission() {
   $permissions = array(
     'administer profile types' =>  array(
       'title' => t('Administer profile types'),
-      'description' => t('Create and delete fields on user profiles, and set their permissions.'),
+      'description' => t('Create and delete fields on profiles, and set their permissions.'),
     ),
     'administer profiles' =>  array(
       'title' => t('Administer profiles'),
-      'description' => t('Edit and view all user profiles.'),
+      'description' => t('Edit and view all profiles.'),
     ),
   );
   // Generate per profile type permissions.
@@ -148,8 +170,9 @@ function profile2_permission() {
  *   Depending whether $type isset, an array of profile types or a single one.
  */
 function profile2_get_types($type_name = NULL) {
-  $types = entity_load_multiple_by_name('profile2_type', isset($type_name) ? array($type_name) : FALSE);
-  return isset($type_name) ? reset($types) : $types;
+  $type_provided = isset($type_name);
+  $types = entity_load_multiple_by_name('profile2_type', $type_provided ? array($type_name) : FALSE);
+  return $type_provided ? reset($types) : $types;
 }
 
 /**
@@ -183,66 +206,12 @@ function profile2_load($pid, $reset = FALSE) {
  *
  * @see entity_load()
  * @see profile2_load()
- * @see profile2_load_by_user()
  */
 function profile2_load_multiple($pids = array(), $conditions = array(), $reset = FALSE) {
   return entity_load('profile2', $pids, $conditions, $reset);
 }
 
 /**
- * Fetch profiles by account.
- *
- * @param $account
- *   The user account to load profiles for, or its uid.
- * @param $type_name
- *   To load a single profile, pass the type name of the profile to load.
- * @return
- *   Either a single profile or an array of profiles keyed by profile type.
- *
- * @see profile2_load_multiple()
- * @see profile2_profile2_delete()
- * @see Profile::save()
- */
-function profile2_load_by_user($account, $type_name = NULL) {
-  // Use a separate query to determine all profile ids per user and cache them.
-  // That way we can look up profiles by id and benefit from the static cache
-  // of the entity loader.
-  $cache = &drupal_static(__FUNCTION__, array());
-  $uid = is_object($account) ? $account->uid : $account;
-
-  if (!isset($cache[$uid])) {
-    if (empty($type_name)) {
-      $profiles = profile2_load_multiple(FALSE, array('uid' => $uid));
-      // Cache ids for further lookups.
-      $cache[$uid] = array();
-      foreach ($profiles as $pid => $profile) {
-        $cache[$uid][$profile->type] = $pid;
-      }
-      return $profiles ? array_combine(array_keys($cache[$uid]), $profiles) : array();
-    }
-    $cache[$uid] = db_select('profile', 'p')
-      ->fields('p', array('type', 'pid'))
-      ->condition('uid', $uid)
-      ->execute()
-      ->fetchAllKeyed();
-  }
-  if (isset($type_name)) {
-    return isset($cache[$uid][$type_name]) ? profile2_load($cache[$uid][$type_name]) : FALSE;
-  }
-  // Return an array containing profiles keyed by profile type.
-  return $cache[$uid] ? array_combine(array_keys($cache[$uid]), profile2_load_multiple($cache[$uid])) : $cache[$uid];
-}
-
-/**
- * Implements hook_profile2_delete().
- */
-function profile2_profile2_delete($profile) {
-  // Clear the static cache from profile2_load_by_user().
-  $cache = &drupal_static('profile2_load_by_user', array());
-  unset($cache[$profile->uid][$profile->type]);
-}
-
-/**
  * Deletes a profile.
  */
 function profile2_delete(Profile $profile) {
@@ -260,18 +229,9 @@ function profile2_delete_multiple(array $pids) {
 }
 
 /**
- * Implements hook_user_delete().
- */
-function profile2_user_delete($account) {
-  foreach (profile2_load_by_user($account) as $profile) {
-    profile2_delete($profile);
-  }
-}
-
-/**
  * Create a new profile object.
  */
-function profile_create(array $values) {
+function profile2_create(array $values) {
   return new Profile($values);
 }
 
@@ -343,63 +303,6 @@ function profile2_profile2_type_delete($type) {
   menu_rebuild();
 }
 
-
-/**
- * Implements hook_user_view().
- */
-function profile2_user_view($account, $view_mode, $langcode) {
-  foreach (profile2_get_types() as $type => $profile_type) {
-    if ($profile_type->userView && $profile = profile2_load_by_user($account, $type)) {
-      if (profile2_access('view', $profile)) {
-        $account->content['profile_' . $type] = array(
-          '#type' => 'user_profile_category',
-          '#title' => $profile->label,
-          '#prefix' => '<a id="profile-' . $profile->type . '"></a>',
-        );
-        $account->content['profile_' . $type]['view'] = $profile->view('account');
-      }
-    }
-  }
-}
-
-/**
- * Implements hook_form_FORM_ID_alter() for the user edit form.
- *
- * @see profile2_form_validate_handler
- * @see profile2_form_submit_handler
- */
-function profile2_form_user_profile_form_alter(&$form, &$form_state) {
-  if (($type = profile2_get_types($form['#user_category'])) && $type->userCategory) {
-    if (empty($form_state['profiles'])) {
-      $profile = profile2_load_by_user($form['#user'], $form['#user_category']);
-      if (empty($profile)) {
-        $profile = profile_create(array('type' => $form['#user_category'], 'uid' => $form['#user']->uid));
-      }
-      $form_state['profiles'][$profile->type] = $profile;
-    }
-    profile2_attach_form($form, $form_state);
-  }
-}
-
-/**
- * Implements hook_form_FORM_ID_alter() for the registration form.
- */
-function profile2_form_user_register_form_alter(&$form, &$form_state) {
-  foreach (profile2_get_types() as $type_name => $profile_type) {
-    if (!empty($profile_type->data['registration'])) {
-      if (empty($form_state['profiles'][$type_name])) {
-        $form_state['profiles'][$type_name] = profile_create(array('type' => $type_name));
-      }
-      profile2_attach_form($form, $form_state);
-      // Wrap each profile form in a fieldset.
-      $form['profile_' . $type_name] += array(
-        '#type' => 'fieldset',
-        '#title' => check_plain($profile_type->label),
-      );
-    }
-  }
-}
-
 /**
  * Attaches the profile forms of the profiles set in
  * $form_state['profiles'].
@@ -460,21 +363,20 @@ function profile2_form_validate_handler(&$form, &$form_state) {
 }
 
 /**
- * Submit handler that builds and saves all profiles in the form.
+ * Submit handler that builds all profiles in the form.
  *
  * @see profile2_attach_form()
  */
 function profile2_form_submit_handler(&$form, &$form_state) {
   profile2_form_submit_build_profile($form, $form_state);
+
   // This is needed as some submit callbacks like user_register_submit() rely on
   // clean form values.
   profile2_form_submit_cleanup($form, $form_state);
 
   foreach ($form_state['profiles'] as $type => $profile) {
-    // During registration set the uid field of the newly created user.
-    if (empty($profile->uid) && isset($form_state['user']->uid)) {
-      $profile->uid = $form_state['user']->uid;
-    }
+    // Allow modules and sub-modules to alter the submitted profile.
+    drupal_alter('profile2_submitted_profile', $profile, $form_state);
     profile2_save($profile);
   }
 }
@@ -508,36 +410,6 @@ function profile2_form_submit_cleanup(&$form, &$form_state) {
 }
 
 /**
- * Implements hook_user_categories().
- */
-function profile2_user_categories() {
-  $data = array();
-  foreach (profile2_get_types() as $type => $info) {
-    if ($info->userCategory) {
-      $data[] = array(
-        'name' => $type,
-        'title' => $info->label,
-        // Add an offset so a weight of 0 appears right of the account category.
-        'weight' => $info->weight + 3,
-        'access callback' => 'profile2_category_access',
-        'access arguments' => array(1, $type)
-      );
-    }
-  }
-  return $data;
-}
-
-/**
- * Menu item access callback - check if a user has access to a profile category.
- */
-function profile2_category_access($account, $type_name) {
-  // As there might be no profile yet, create a new object for being able to run
-  // a proper access check.
-  $profile = profile_create(array('type' => $type_name, 'uid' => $account->uid));
-  return ($account->uid > 0 && $profile->type()->userCategory && profile2_access('edit', $profile));
-}
-
-/**
  * Determines whether the given user has access to a profile.
  *
  * @param $op
@@ -548,11 +420,12 @@ function profile2_category_access($account, $type_name) {
  *   all profiles is determined.
  * @param $account
  *   The user to check for. Leave it to NULL to check for the global user.
+ *
  * @return boolean
  *   Whether access is allowed or not.
  *
  * @see hook_profile2_access()
- * @see profile2_profile2_access()
+ * @see profile2_user_profile2_access()
  */
 function profile2_access($op, $profile = NULL, $account = NULL) {
   if (user_access('administer profiles', $account)) {
@@ -576,23 +449,6 @@ function profile2_access($op, $profile = NULL, $account = NULL) {
 }
 
 /**
- * Implements hook_profile2_access().
- */
-function profile2_profile2_access($op, $profile = NULL, $account = NULL) {
-  // Don't grant access for users to delete their profile.
-  if (isset($profile) && ($type_name = $profile->type) && $op != 'delete') {
-    if (user_access("$op any $type_name profile", $account)) {
-      return TRUE;
-    }
-    $account = isset($account) ? $account : $GLOBALS['user'];
-    if (isset($profile->uid) && $profile->uid == $account->uid && user_access("$op own $type_name profile", $account)) {
-      return TRUE;
-    }
-  }
-  // Do not explicitly deny access so others may still grant access.
-}
-
-/**
  * Access callback for the entity API.
  */
 function profile2_type_access($op, $type = NULL, $account = NULL) {
@@ -620,10 +476,6 @@ function profile2_theme() {
 class Profile extends Entity {
 
   public function __construct($values = array()) {
-    if (isset($values['user'])) {
-      $this->setUser($values['user']);
-      unset($values['user']);
-    }
     if (isset($values['type']) && is_object($values['type'])) {
       $values['type'] = $values['type']->type;
     }
@@ -631,23 +483,6 @@ class Profile extends Entity {
   }
 
   /**
-   * Returns the user owning this profile.
-   */
-  public function user() {
-    return user_load($this->uid);
-  }
-
-  /**
-   * Sets a new user owning this profile.
-   *
-   * @param $account
-   *   The user account object or the user account id (uid).
-   */
-  public function setUser($account) {
-    $this->uid = is_object($account) ? $account->uid : $account;
-  }
-
-  /**
    * Gets the associated profile type object.
    *
    * @return ProfileType
@@ -676,30 +511,14 @@ class Profile extends Entity {
     return $uri['path'];
   }
 
-  public function defaultUri() {
-    return array(
-      'path' => 'user/' . $this->uid,
-      'options' => array('fragment' => 'profile-' . $this->type),
-    );
-  }
-
   public function buildContent($view_mode = 'full', $langcode = NULL) {
     $content = array();
     // Assume newly create objects are still empty.
-    if (!empty($this->is_new)) {
+    if (empty($this->pid)) {
       $content['empty']['#markup'] = '<em class="profile2-no-data">' . t('There is no profile data yet.') . '</em>';
     }
     return entity_get_controller($this->entityType)->buildContent($this, $view_mode, $langcode, $content);
   }
-
-  public function save() {
-    parent::save();
-    // Update the static cache from profile2_load_by_user().
-    $cache = &drupal_static('profile2_load_by_user', array());
-    if (isset($cache[$this->uid])) {
-      $cache[$this->uid][$this->type] = $this->pid;
-    }
-  }
 }
 
 /**
@@ -708,16 +527,6 @@ class Profile extends Entity {
  */
 class ProfileType extends Entity {
 
-  /**
-   * Whether the profile type appears in the user categories.
-   */
-  public $userCategory = TRUE;
-
-  /**
-   * Whether the profile is displayed on the user account page.
-   */
-  public $userView = TRUE;
-
   public $type;
   public $label;
   public $weight = 0;
@@ -733,57 +542,56 @@ class ProfileType extends Entity {
    * as any fixed profile type.
    */
   public function isLocked() {
-    return isset($this->status) && empty($this->is_new) && (($this->status & ENTITY_IN_CODE) || ($this->status & ENTITY_FIXED));
+    return isset($this->status) && !empty($this->pid) && (($this->status & ENTITY_IN_CODE) || ($this->status & ENTITY_FIXED));
   }
 }
 
 /**
- * Implements hook_form_FORMID_alter().
- *
- * Adds a checkbox for controlling field view access to fields added to
- * profiles.
+ * Extend EntityAPIControllerExportable.
  */
-function profile2_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
-  if ($form['instance']['entity_type']['#value'] == 'profile2') {
-    $form['field']['settings']['profile2_private'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Make the content of this field private.'),
-      '#default_value' => !empty($form['#field']['settings']['profile2_private']),
-      '#description' => t('If checked, the content of this field is only shown to the profile owner and administrators.'),
-    );
-  }
-  else {
-    // Add the value to the form so it isn't lost.
-    $form['field']['settings']['profile2_private'] = array(
-      '#type' => 'value',
-      '#value' => !empty($form['#field']['settings']['profile2_private']),
-    );
-  }
-}
+class ProfileType2ControllerExportable extends EntityAPIControllerExportable {
 
-/**
- * Implements hook_field_access().
- */
-function profile2_field_access($op, $field, $entity_type, $profile = NULL, $account = NULL) {
-  if ($entity_type == 'profile2' && $op == 'view' && !empty($field['settings']['profile2_private']) && !user_access('administer profiles', $account)) {
-    // For profiles, deny general view access for private fields.
-    if (!isset($profile)) {
-      return FALSE;
+  /**
+   * Overwrite parent::load() to attach also entity types.
+   */
+  public function load($ids = array(), $conditions = array()) {
+    $profiles = parent::load($ids, $conditions);
+    foreach ($profiles as $pid => $profile) {
+      $entities = db_query("SELECT entity_type FROM {profile_type_entity} WHERE type = :type", array(':type' => $profile->type))->fetchCol();
+      $profiles[$pid]->entity = $entities ? $entities : array();
     }
-    // Also deny view access, if someone else views a private field.
-    $account = isset($account) ? $account : $GLOBALS['user'];
-    if ($account->uid != $profile->uid) {
-      return FALSE;
+    return $profiles;
+  }
+
+  /**
+   * Overwrite parent::delete() to delete the profile_type - entity relations.
+   */
+  public function delete($ids, DatabaseTransaction $transaction = NULL) {
+    if ($ids) {
+      db_delete('profile_type_entity')
+        ->condition('type', $ids, 'IN')
+        ->execute();
     }
+    parent::delete($ids, $transaction);
   }
-}
 
-/**
- * Entity metadata callback to load profiles for the given user account.
- */
-function profile2_user_get_properties($account, array $options, $name) {
-  // Remove the leading 'profile_' from the property name to get the type name.
-  $profile = profile2_load_by_user($account, substr($name, 8));
-  return $profile ? $profile : NULL;
+  /**
+   * Overwrite parent::save() to save the profile_type - entity relations.
+   */
+  public function save($profile_type, DatabaseTransaction $transaction = NULL) {
+    $type = $profile_type->type;
+    db_delete('profile_type_entity')
+      ->condition('type', $type)
+      ->execute();
+
+    if ($profile_type->entity) {
+      $query = db_insert('profile_type_entity')
+        ->fields(array('type', 'entity_type'));
+      foreach ($profile_type->entity as $entity_type) {
+        $query->values(array('type' => $type, 'entity_type' => $entity_type));
+      }
+      $query->execute();
+    }
+    parent::save($profile_type, $transaction);
+  }
 }
-
diff --git a/sites/all/modules/profile2/profile2.test b/sites/all/modules/profile2/profile2.test
deleted file mode 100644
index 5f1b51c..0000000
--- a/sites/all/modules/profile2/profile2.test
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-
-/**
- * Test basic CRUD functionality.
- */
-class ProfileCRUDTestCase extends DrupalWebTestCase {
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Editing profiles',
-      'description' => 'Tests basic CRUD and editing of profiles.',
-      'group' => 'Profile2',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('profile2', 'locale');
-
-    profile2_type_save(new ProfileType(array(
-      'type' => 'test',
-      'label' => 'label',
-      'weight' => 0
-    )));
-    profile2_type_save(new ProfileType(array(
-      'type' => 'test2',
-      'label' => 'label2',
-      'weight' => 2
-    )));
-    profile2_load_multiple(FALSE, array(), TRUE);
-
-    // Add a field to main type, which is created during module installation.
-    $field = array(
-      'field_name' => 'profile_fullname',
-      'type' => 'text',
-      'cardinality' => 1,
-      'translatable' => FALSE,
-    );
-    field_create_field($field);
-    $instance = array(
-      'entity_type' => 'profile2',
-      'field_name' => 'profile_fullname',
-      'bundle' => 'main',
-      'label' => 'Full name',
-      'description' => 'Specify your first and last name.',
-      'widget' => array(
-        'type' => 'text_textfield',
-        'weight' => 0,
-      ),
-    );
-    field_create_instance($instance);
-  }
-
-  /**
-   * Tests CRUD for a profile related to a user and one unrelated to a user.
-   */
-  function testCRUD() {
-    $user1 = $this->drupalCreateUser();
-    // Create profiles for the user1 and unrelated to a user.
-    profile2_save(profile_create(array('type' => 'test', 'uid' => $user1->uid)));
-    profile2_save(profile_create(array('type' => 'test2', 'uid' => $user1->uid)));
-    $profile = profile_create(array('type' => 'test', 'uid' => NULL));
-    profile2_save($profile);
-
-    $profiles = profile2_load_by_user($user1);
-    $this->assertEqual($profiles['test']->label(), 'label', 'Created and loaded profile 1.');
-    $this->assertEqual($profiles['test2']->label(), 'label2', 'Created and loaded profile 2.');
-
-    // Test looking up from static cache works also.
-    $profiles = profile2_load_by_user($user1);
-    $this->assertEqual($profiles['test']->label, 'label', 'Looked up profiles again.');
-
-    $loaded = profile2_load($profile->pid);
-    $this->assertEqual($loaded->pid, $profile->pid, 'Loaded profile unrelated to a user.');
-
-    profile2_delete($profiles['test']);
-    $profiles2 = profile2_load_by_user($user1);
-    $this->assertEqual(array_keys($profiles2), array('test2'), 'Profile successfully deleted.');
-
-    profile2_save($profiles2['test2']);
-    $this->assertEqual($profiles['test2']->pid, $profiles2['test2']->pid, 'Profile successfully updated.');
-
-    // Delete a profile type.
-    profile2_type_delete(profile2_get_types('test'));
-    // Try deleting multiple profiles by deleting all existing profiles.
-    $pids = array_keys(profile2_load_multiple(FALSE));
-    profile2_delete_multiple($pids);
-  }
-
-  /**
-   * Test registration integration.
-   */
-  function testRegistrationIntegration() {
-    // Allow registration by site visitors without administrator approval.
-    variable_set('user_register', 1);
-    $edit = array();
-    $edit['name'] = $name = $this->randomName();
-    $edit['mail'] = $mail = $edit['name'] . '@example.com';
-    $edit['profile_main[profile_fullname][und][0][value]'] = $this->randomName();
-    $this->drupalPost('user/register', $edit, t('Create new account'));
-    $this->assertText(t('A welcome message with further instructions has been sent to your e-mail address.'), t('User registered successfully.'));
-    $return = user_load_multiple(array(), array('name' => $name, 'mail' => $mail));
-    $new_user = reset($return);
-    $this->assertTrue($new_user->status, t('New account is active after registration.'));
-    $this->assertEqual(profile2_load_by_user($new_user, 'main')->profile_fullname[LANGUAGE_NONE][0]['value'], $edit['profile_main[profile_fullname][und][0][value]'], 'Profile created.');
-  }
-
-  /**
-   * Test basic edit and display.
-   */
-  function testEditAndDisplay() {
-    user_role_revoke_permissions(DRUPAL_AUTHENTICATED_RID, array('edit own main profile', 'view own main profile'));
-    $user1 = $this->drupalCreateUser();
-    $this->drupalLogin($user1);
-    // Make sure access is denied to the profile.
-    $this->drupalGet('user/' . $user1->uid . '/edit/main');
-    $this->assertText(t('Access denied'), 'Access has been denied.');
-
-    // Test creating a profile manually (e.g. by an admin) and ensure the user
-    // may not see it.
-    profile_create(array('type' => 'main', 'uid' => $user1->uid))->save();
-    $this->drupalGet('user/' . $user1->uid);
-    $this->assertNoText(t('Main profile'), 'Profile data is not visible to the owner.');
-
-    $user2 = $this->drupalCreateUser(array('edit own main profile', 'view own main profile'));
-    $this->drupalLogin($user2);
-
-    // Create profiles for the user2.
-    $edit['profile_main[profile_fullname][und][0][value]'] = $this->randomName();
-    $this->drupalPost('user/' . $user2->uid . '/edit/main', $edit, t('Save'));
-    $this->assertText(t('The changes have been saved.'), 'Profile saved.');
-    $this->assertEqual(profile2_load_by_user($user2, 'main')->profile_fullname[LANGUAGE_NONE][0]['value'], $edit['profile_main[profile_fullname][und][0][value]'], 'Profile edited.');
-
-    $this->drupalGet('user/' . $user2->uid);
-    $this->assertText(check_plain($edit['profile_main[profile_fullname][und][0][value]']), 'Profile displayed.');
-  }
-
-}
-
-- 
1.7.5.4

