You are here

fb_autopost_entity.module in Facebook Autopost 7

Module implementation file

File

fb_autopost_entity/fb_autopost_entity.module
View source
<?php

/**
 * @file
 * Module implementation file
 */

/**
 * Implements hook_menu().
 */
function fb_autopost_entity_menu() {
  $items['facebook-publication/%facebook_publication'] = array(
    'title callback' => 'facebook_publication_title',
    'title arguments' => array(
      1,
    ),
    'page callback' => 'facebook_publication_view',
    'page arguments' => array(
      1,
    ),
    'access callback' => 'facebook_publication_access',
    'access arguments' => array(
      'view',
      1,
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Title callback for a Facebook Publication page.
 */
function facebook_publication_title($facebook_publication) {
  return $facebook_publication->label;
}

/**
 * Implements hook_fb_autopost_publication_publish().
 */
function fb_autopost_entity_fb_autopost_publication_publish($publication, $result) {

  // If the publication being published came from an entity, invokes
  // hook_fb_autopost_publication_entity_publish.
  // Publications that started with entities have an extra 'entity' field.
  if (!empty($publication['entity'])) {
    $publication_entity = unserialize($publication['entity']);
    module_invoke_all('fb_autopost_publication_entity_publish', $publication_entity, $result);
  }
}

/**
 * Implements hook_entity_info().
 */
function fb_autopost_entity_entity_info() {
  $return = array(
    'facebook_publication' => array(
      'label' => t('Facebook publication'),
      'plural label' => t('Facebook publications'),
      'description' => t('Facebook publications to be displayed in the configured Facebook page(s).'),
      'entity class' => 'FacebookPublicationEntity',
      'controller class' => 'EntityAPIController',
      'base table' => 'facebook_publication',
      'fieldable' => TRUE,
      'view modes' => array(
        'full' => array(
          'label' => t('Full view'),
          'custom settings' => FALSE,
        ),
      ),
      'entity keys' => array(
        'id' => 'fbpid',
        'bundle' => 'type',
        'label' => 'label',
      ),
      'bundles' => array(),
      'bundle keys' => array(
        'bundle' => 'type',
      ),
      'uri callback' => 'entity_class_uri',
      'access callback' => 'facebook_publication_access',
      'module' => 'fb_autopost_entity',
      'metadata controller class' => 'FacebookPublicationMetadataController',
    ),
  );

  // Add bundle info but bypass entity_load() as we cannot use it here.
  $types = db_select('facebook_publication_type', 'p')
    ->fields('p')
    ->execute()
    ->fetchAllAssoc('type');
  foreach ($types as $type => $info) {
    $return['facebook_publication']['bundles'][$type] = array(
      'label' => $info->label,
      'admin' => array(
        'path' => 'admin/structure/facebook-publications/manage/%facebook_publication_type',
        'real path' => 'admin/structure/facebook-publications/manage/' . $type,
        'bundle argument' => 4,
        'access arguments' => array(
          'administer facebook publications',
        ),
      ),
    );
  }

  // Support entity cache module.
  if (module_exists('entitycache')) {
    $return['facebook_publication']['field cache'] = FALSE;
    $return['facebook_publication']['entity cache'] = TRUE;
  }
  $return['facebook_publication_type'] = array(
    'label' => t('Facebook publication type'),
    'plural label' => t('Facebook publication types'),
    'description' => t('Facebook publication types of Graph API.'),
    'entity class' => 'FacebookPublicationTypeEntity',
    'controller class' => 'EntityAPIControllerExportable',
    'base table' => 'facebook_publication_type',
    'fieldable' => FALSE,
    'bundle of' => 'facebook_publication',
    'exportable' => TRUE,
    'entity keys' => array(
      'id' => 'id',
      'name' => 'type',
      'label' => 'label',
    ),
    'access callback' => 'facebook_publication_type_access',
    'module' => 'fb_autopost_entity',
    // Enable the entity API's admin UI.
    'admin ui' => array(
      'path' => 'admin/structure/facebook-publications',
      'file' => 'fb_autopost_entity.admin.inc',
      'controller class' => 'FacebookPublicationTypeUIController',
    ),
  );
  return $return;
}

/**
 * Menu argument loader; Load a Facebook publication type by string.
 *
 * @param string $type
 *   The machine-readable name of a Facebook publication type to load.
 *
 * @return array
 *   A Facebook publication type array or FALSE if $type does not exist.
 */
function facebook_publication_type_load($type) {
  return facebook_publication_get_types($type);
}

/**
 * Implements hook_permission().
 */
function fb_autopost_entity_permission() {
  $permissions = array(
    'administer facebook publication types' => array(
      'title' => t('Administer Facebook publication types'),
      'description' => t('Create and delete fields on Facebook publications, and set their permissions.'),
    ),
    'administer facebook publications' => array(
      'title' => t('Administer Facebook publications'),
      'description' => t('Edit and view all Facebook publications.'),
    ),
  );

  // Generate per Facebook publication type permissions.
  foreach (facebook_publication_get_types() as $type) {
    $type_name = check_plain($type->type);
    $permissions += array(
      "edit own {$type_name} facebook publication" => array(
        'title' => t('%type_name: Edit own Facebook publication', array(
          '%type_name' => $type->label,
        )),
      ),
      "edit any {$type_name} facebook publication" => array(
        'title' => t('%type_name: Edit any Facebook publication', array(
          '%type_name' => $type->label,
        )),
      ),
      "view own {$type_name} facebook publication" => array(
        'title' => t('%type_name: View own Facebook publication', array(
          '%type_name' => $type->label,
        )),
      ),
      "view any {$type_name} facebook publication" => array(
        'title' => t('%type_name: View any Facebook publication', array(
          '%type_name' => $type->label,
        )),
      ),
    );
  }
  return $permissions;
}

/**
 * Gets an array of all Facebook publication types, keyed by the type name.
 *
 * @param string $type_name
 *   If set, the type with the given name is returned.
 *
 * @return FacebookPublicationTypeEntity[]
 *   Depending whether $type isset, an array of Facebook publication types or a
 * single one.
 */
function facebook_publication_get_types($type_name = NULL) {
  $types = entity_load_multiple_by_name('facebook_publication_type', isset($type_name) ? array(
    $type_name,
  ) : FALSE);
  return isset($type_name) ? reset($types) : $types;
}

/**
 * Fetch a Facebook publication object.
 *
 * @param int $fbpid
 *   Integer specifying the Facebook publication id.
 * @param bool $reset
 *   A boolean indicating that the internal cache should be reset.
 *
 * @return FacebookPublicationEntity
 *   A fully-loaded $publications object or FALSE if it cannot be loaded.
 *
 * @see facebook_publication_load_multiple()
 */
function facebook_publication_load($fbpid, $reset = FALSE) {
  $publications = facebook_publication_load_multiple(array(
    $fbpid,
  ), array(), $reset);
  return reset($publications);
}

/**
 * Load multiple Facebook publications based on certain conditions.
 *
 * @param array $fbpids
 *   An array of Facebook publication IDs.
 * @param array $conditions
 *   An array of conditions to match against the {facebook_publication} table.
 * @param bool $reset
 *   A boolean indicating that the internal cache should be reset.
 *
 * @return array
 *   An array of Facebook publication objects, indexed by pid.
 *
 * @see entity_load()
 * @see facebook_publication_load()
 */
function facebook_publication_load_multiple($fbpids = array(), $conditions = array(), $reset = FALSE) {
  return entity_load('facebook_publication', $fbpids, $conditions, $reset);
}

/**
 * Deletes a Facebook publication.
 */
function facebook_publication_delete(FacebookPublicationEntity $publication) {
  $publication
    ->delete();
}

/**
 * Delete multiple Facebook publications.
 *
 * @param array $fbpids
 *   An array of Facebook publication IDs.
 */
function facebook_publication_delete_multiple(array $fbpids) {
  entity_get_controller('facebook_publication')
    ->delete($fbpids);
}

/**
 * Create a new Facebook publication object.
 */
function facebook_publication_create(array $values) {
  return new FacebookPublicationEntity($values);
}

/**
 * Saves a Facebook publication to the database.
 *
 * @param FacebookPublicationEntity $publication
 *   The FacebookPublicationEntity object.
 */
function facebook_publication_save(FacebookPublicationEntity $publication) {
  return $publication
    ->save();
}

/**
 * Saves a Facebook publication type to the db.
 */
function facebook_publication_type_save(FacebookPublicationTypeEntity $type) {
  $type
    ->save();
}

/**
 * Deletes a Facebook publication type from.
 */
function facebook_publication_type_delete(FacebookPublicationTypeEntity $type) {
  $type
    ->delete();
}

/**
 * Implements hook_facebook_publication_type_insert().
 */
function fb_autopost_entity_facebook_publication_type_insert(FacebookPublicationTypeEntity $type) {

  // Always rebuild the menu in case a Facebook publication type is inserted or
  // changed. In order to avoid possible multiple rebuilds of modules we just do
  // it always but once here.
  variable_set('menu_rebuild_needed', TRUE);
}

/**
 * Implements hook_facebook_publication_type_update().
 */
function fb_autopost_entity_facebook_publication_type_update(FacebookPublicationTypeEntity $type) {

  // @see fb_autopost_entity_facebook_publication_type_insert()
  variable_set('menu_rebuild_needed', TRUE);
}

/**
 * Implements hook_facebook_publication_type_delete().
 */
function fb_autopost_entity_facebook_publication_type_delete($type) {

  // Delete all Facebook publications of this type.
  if ($fbpids = array_keys(facebook_publication_load_multiple(FALSE, array(
    'type' => $type->type,
  )))) {
    facebook_publication_delete_multiple($fbpids);
  }

  // @see fb_autopost_entity_facebook_publication_type_insert()
  variable_set('menu_rebuild_needed', TRUE);
}

/**
 * Determines whether the given user has access to a Facebook publication.
 *
 * @param string $op
 *   The operation being performed. One of 'view', 'update', 'create', 'delete'
 *   or just 'edit' (being the same as 'create' or 'update').
 * @param FacebookPublicationEntity $publication
 *   (optional) A Facebook publication to check access for. If nothing is given,
 * access for all publications is determined.
 * @param object $account
 *   The user to check for. Leave it to NULL to check for the global user.
 *
 * @return bool
 *   Whether access is allowed or not.
 *
 * @see hook_facebook_publication_access()
 * @see fb_autopost_entity_facebook_publication_access()
 */
function facebook_publication_access($op, $publication = NULL, $account = NULL) {
  if (user_access('administer facebook publications', $account)) {
    return TRUE;
  }
  if ($op == 'create' || $op == 'update') {
    $op = 'edit';
  }

  // Allow modules to grant / deny access.
  $access = module_invoke_all('facebook_publication_access', $op, $publication, $account);

  // Only grant access if at least one module granted access and no one denied
  // access.
  if (in_array(FALSE, $access, TRUE)) {
    return FALSE;
  }
  elseif (in_array(TRUE, $access, TRUE)) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Implements hook_facebook_publication_access().
 */
function fb_autopost_entity_facebook_publication_access($op, $publication = NULL, $account = NULL) {

  // Don't grant access for users to delete their Facebook publications.
  if (isset($publication) && ($type_name = $publication->type) && $op != 'delete') {
    if (user_access("{$op} any {$type_name} facebook publication", $account)) {
      return TRUE;
    }
    $account = isset($account) ? $account : $GLOBALS['user'];
    if (isset($publication->uid) && $publication->uid == $account->uid && user_access("{$op} own {$type_name} facebook publication", $account)) {
      return TRUE;
    }
  }

  // Do not explicitly deny access so others may still grant access.
}

/**
 * Access callback for the entity API.
 */
function facebook_publication_type_access($op, $type = NULL, $account = NULL) {
  return user_access('administer facebook publication types', $account);
}

/**
 * Renders a FacebookPublicationEntity.
 */
function facebook_publication_view(FacebookPublicationEntity $publication) {
  $entities = entity_view('facebook_publication', array(
    $publication,
  ));
  return reset($entities);
}

/**
 * The class used for Facebook publication entities.
 */
class FacebookPublicationEntity extends Entity {

  /**
   * The Facebook publication id.
   *
   * @var integer
   */
  public $fbpid;

  /**
   * The name of the Facebook publication type.
   *
   * @var string
   */
  public $type;

  /**
   * The Facebook publication label.
   *
   * @var string
   */
  public $label;

  /**
   * The user id of the Facebook publication owner.
   *
   * @var integer
   */
  public $uid;

  /**
   * The Unix timestamp when the Facebook publication was created.
   *
   * @var integer
   */
  public $created;

  /**
   * The Unix timestamp when the Facebook publication was most recently saved.
   *
   * @var integer
   */
  public $changed;

  /**
   * The ID string returned from Facebook on publication.
   *
   * @var string
   */
  public $facebook_id;

  /**
   * Entity constructor.
   */
  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;
    }
    if (!isset($values['label']) && isset($values['type']) && ($type = facebook_publication_get_types($values['type']))) {

      // Initialize the label with the type label, so newly created publications
      // have that as interim label.
      $values['label'] = $type->label;
    }
    parent::__construct($values, 'facebook_publication');
  }

  /**
   * Returns the user owning this Facebook publication.
   */
  public function user() {
    return user_load($this->uid);
  }

  /**
   * Sets a new user owning this Facebook publication.
   *
   * @param object $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 Facebook publication type object.
   *
   * @return FacebookPublicationTypeEntity
   *   Returns the type entity.
   */
  public function type() {
    return facebook_publication_get_types($this->type);
  }

  /**
   * Gets the associated facebook_id.
   *
   * @return string
   *   String representing the Facebook ID.
   */
  public function facebookid() {
    return $this->facebook_id;
  }

  /**
   * Returns the full url() for the Facebook publication.
   */
  public function url() {
    $uri = $this
      ->uri();
    return url($uri['path'], $uri);
  }

  /**
   * Returns the drupal path to this Facebook publication.
   */
  public function path() {
    $uri = $this
      ->uri();
    return $uri['path'];
  }

  /**
   * Gets the default URI for the publication.
   */
  public function defaultUri() {
    return array(
      // TODO: Define this URL in hook_menu.
      'path' => 'facebook-publication/' . $this->fbpid,
    );
  }

  /**
   * Build entity content based on $view_mode and $lagcode.
   */
  public function buildContent($view_mode = 'full', $langcode = NULL) {
    $content = array();

    // Assume newly create objects are still empty.
    if (!empty($this->is_new)) {
      $content['empty']['#markup'] = '<em class="facebook-pulbication-no-data">' . t('There is no Facebook publication data yet.') . '</em>';
    }
    return entity_get_controller($this->entityType)
      ->buildContent($this, $view_mode, $langcode, $content);
  }

  /**
   * Save the entity.
   */
  public function save() {

    // Care about setting created and changed values. But do not automatically
    // set a created values for already existing Facebook publications.
    if (empty($this->created) && (!empty($this->is_new) || !$this->fbpid)) {
      $this->created = REQUEST_TIME;
    }
    $this->changed = REQUEST_TIME;
    parent::save();
  }

  /**
   * Get the property names out of the field names associated to this entity.
   *
   * @param array $field_names
   *   A numeric array containing the field names to translate.
   *
   * @return array
   *   A keyed array with field name => property name.
   */
  public function getFieldProperties($field_names = NULL) {
    if (empty($field_names)) {

      // Get all the field names associated with this entity bundle.
      $field_names = array_keys(field_info_instances('facebook_publication', $publication->type));
    }
    $output = array();
    foreach ($field_names as $field_name) {

      // Remove 'field_facebook_' prefix from field names.
      $output[$field_name] = substr($field_name, strlen('field_facebook_'));
    }

    // Allow other modules to alter this default behavior.
    drupal_alter('field_property_data', $output);
    return $output;
  }

}

/**
 * Use a separate class for Facebook publication types so we can specify some
 * defaults modules may alter.
 */
class FacebookPublicationTypeEntity extends Entity {
  public $type;
  public $label;

  /**
   * Entity type constructor.
   */
  public function __construct($values = array()) {
    parent::__construct($values, 'facebook_publication_type');
  }

  /**
   * Returns whether the Facebook publication type is locked.
   *
   * Facebook publication types provided in code are automatically treated as
   * locked, as well as any fixed Facebook publication type. Locked may not be
   * deleted or renamed.
   */
  public function isLocked() {
    return isset($this->status) && empty($this->is_new) && ($this->status & ENTITY_IN_CODE || $this->status & ENTITY_FIXED);
  }

}

/**
 * Helper function to translate from field names to property names for the SDK.
 *
 * @param FacebookPublicationEntity $publication
 *   Entity to extract the properties from.
 *
 * @return array
 *   An array of property names with their corresponding values
 */
function fb_autopost_entity_get_properties(FacebookPublicationEntity $publication) {
  $output = array();

  // By default assume the properties are like field names minus
  // 'field_facebook_'. Get all the field names associated with this entity
  // bundle.
  $field_names = array_keys(field_info_instances('facebook_publication', $publication->type));

  // We will need a entity wrapper to access the field values.
  $wrapper = entity_metadata_wrapper('facebook_publication', $publication);

  // Get a keyed array to translate field names into Facebook property names.
  $field_properties = $publication
    ->getFieldProperties($field_names);

  // Iterate over each field to fetch the actual value.
  foreach ($field_names as $field_name) {
    $value = $wrapper->{$field_name}
      ->value();
    if (isset($value)) {
      $output[$field_properties[$field_name]] = $value;
    }
  }
  return $output;
}

/**
 * Factory method.
 *
 * @param string $type
 *   Facebook publication type.
 */
function facebook_autopost_entity($type) {
  switch ($type) {
    case 'photo':
      $fb = new FBAutopostEntityPhoto();
      break;
    case 'event':
      $fb = new FBAutopostEntityEvent();
      break;
    case 'post':
      $fb = new FBAutopostEntityPost();
      break;
    default:
      $fb = new FBAutopostEntity();
      break;
  }
  if ($type) {
    $fb
      ->setType($type);
  }

  // Allow other modules to alter $fb. Useful for altering the underlying
  // BaseFacebook object for things like adding proxy support to curl options
  drupal_alter('facebook_autopost_entiy_fb', $fb);
  return $fb;
}

/**
 * Implements hook_views_api().
 */
function fb_autopost_entity_views_api() {
  return array(
    'api' => 3,
  );
}

Functions

Namesort descending Description
facebook_autopost_entity Factory method.
facebook_publication_access Determines whether the given user has access to a Facebook publication.
facebook_publication_create Create a new Facebook publication object.
facebook_publication_delete Deletes a Facebook publication.
facebook_publication_delete_multiple Delete multiple Facebook publications.
facebook_publication_get_types Gets an array of all Facebook publication types, keyed by the type name.
facebook_publication_load Fetch a Facebook publication object.
facebook_publication_load_multiple Load multiple Facebook publications based on certain conditions.
facebook_publication_save Saves a Facebook publication to the database.
facebook_publication_title Title callback for a Facebook Publication page.
facebook_publication_type_access Access callback for the entity API.
facebook_publication_type_delete Deletes a Facebook publication type from.
facebook_publication_type_load Menu argument loader; Load a Facebook publication type by string.
facebook_publication_type_save Saves a Facebook publication type to the db.
facebook_publication_view Renders a FacebookPublicationEntity.
fb_autopost_entity_entity_info Implements hook_entity_info().
fb_autopost_entity_facebook_publication_access Implements hook_facebook_publication_access().
fb_autopost_entity_facebook_publication_type_delete Implements hook_facebook_publication_type_delete().
fb_autopost_entity_facebook_publication_type_insert Implements hook_facebook_publication_type_insert().
fb_autopost_entity_facebook_publication_type_update Implements hook_facebook_publication_type_update().
fb_autopost_entity_fb_autopost_publication_publish Implements hook_fb_autopost_publication_publish().
fb_autopost_entity_get_properties Helper function to translate from field names to property names for the SDK.
fb_autopost_entity_menu Implements hook_menu().
fb_autopost_entity_permission Implements hook_permission().
fb_autopost_entity_views_api Implements hook_views_api().

Classes

Namesort descending Description
FacebookPublicationEntity The class used for Facebook publication entities.
FacebookPublicationTypeEntity Use a separate class for Facebook publication types so we can specify some defaults modules may alter.