<?php

/**
 * @file
 * Contains EntityReferenceViewsTestCase.
 */

/**
 * Test for Entity Reference integration with Views.
 */
class EntityReferenceViewsTestCase extends DrupalWebTestCase {

  /**
   * An administrator user.
   *
   * @var object
   */
  public $adminUser;

  /**
   * An unprivileged user.
   *
   * @var object
   */
  public $unprivilegedUser;

  /**
   * The content type that is created.
   *
   * @var string
   */
  protected $referencingContentType;

  /**
   * {@inheritdoc}
   */
  public static function getInfo() {
    return array(
      'name' => 'Entity Reference integration with Views',
      'description' => 'Test Views Selection',
      'group' => 'Entity Reference',
    );
  }

  /**
   * {@inheritdoc}
   */
  public function setUp() {
    parent::setUp();
    // Take control the order the modules are loaded to ensure views loads
    // before entityreference.
    module_enable(array(
      'ctools',
      'entity',
      'views',
      'entityreference',
      'entityreference_views_test',
    ), FALSE);
    $this->resetAll();

    // Setup and login admin user.
    $this->createUsers();
    $this->drupalLogin($this->adminUser);

    // Create referencing content type.
    $referencing_content_type = $this->drupalCreateContentType();
    $this->referencingContentType = $referencing_content_type->type;

    // Check plugin definition is available.
    $plugin = ctools_get_plugins('entityreference', 'selection', 'views');
    $this->assertTrue($plugin, t('Views selection plugin is available.'));
  }

  /**
   * Tests EntityReference_SelectionHandler_Views works with Taxonomy Terms.
   */
  public function testSelectTermsWithViewsSelectionHandler() {
    // Create entityreference Views display.
    $view_name = 'test_entityreference_select_node';
    $display_name = 'entityreference_1';
    $this->createTermEntityReferenceView($view_name, $display_name);

    // Ensure the view can be initialized.
    $view = views_get_view($view_name);
    $this->assertTrue($view, t('The view is loaded: @view_name', array('@view_name' => $view_name)));
    $this->assertTrue(isset($view->display[$display_name]), t('The view display is loaded: @view_display', array('@view_display' => "$view_name:$display_name")));
    $this->assertTrue($view->access($display_name), t('The view display has access: @view_display ', array('@view_display' => "$view_name:$display_name")));

    // Create the referenced vocabulary.
    $vocabulary_referenced = $this->createVocabulary();

    // Create a field to reference the taxonomy terms.
    $field_name = 'field_' . $vocabulary_referenced;
    $field = array(
      'field_name' => $field_name,
      'settings' => array(
        'handler' => 'views',
        'target_type' => 'taxonomy_term',
        'handler_settings' => array(
          'view' => array(
            'view_name' => $view_name,
            'display_name' => $display_name,
            'args' => array(),
          ),
          'behaviors' => array(
            'views-select-list' => array(
              'status' => 0,
            ),
          ),
        ),
      ),
    );

    $field_instance = array(
      'field_name' => $field_name,
      'bundle' => $this->referencingContentType,
    );
    $this->createEntityReferenceFieldForNode($field, $field_instance);

    // Get a selection handler for this field.
    $handler = entityreference_get_selection_handler($field, $field_instance);
    $handler_class = get_class($handler);
    $this->assertEqual('EntityReference_SelectionHandler_Views', $handler_class, t('@handler_class is EntityReference_SelectionHandler_Views is used for taxonomy reference field: @field_name', array(
      '@field_name' => $field_name,
      '@handler_class' => $handler_class,
    )));

    $result = $handler->getReferencableEntities();
    $this->assertFalse($result, 0, t('There are no nodes to reference.'));

    // Add 3 referenced terms.
    $vocabulary = taxonomy_vocabulary_machine_name_load($vocabulary_referenced);
    $this->createTerm(array('vid' => $vocabulary->vid));
    $this->createTerm(array('vid' => $vocabulary->vid));
    $this->createTerm(array('vid' => $vocabulary->vid));

    $result = $handler->getReferencableEntities();
    $count = (int) (!empty($result[$vocabulary_referenced])) ? count($result[$vocabulary_referenced]) : 0;
    $this->assertIdentical($count, 3, t('There are @count of 3 referencable terms.', array('@count' => $count)));

    // Login as an unprivileged user.
    $this->drupalLogin($this->unprivilegedUser);
    $GLOBALS['user'] = $this->unprivilegedUser;

    // Check access.
    $result = $handler->getReferencableEntities();
    $count = (int) (!empty($result[$vocabulary_referenced])) ? count($result[$vocabulary_referenced]) : 0;
    $this->assertIdentical($count, 1, t('There are @count of 1 referencable terms for an unprivileged user.', array('@count' => $count)));
  }

  /**
   * Tests EntityReference_SelectionHandler_Views works with Nodes.
   */
  public function testSelectNodesWithViewsSelectionHandler() {
    $view_name = 'test_entityreference_select_node';
    $display_name = 'entityreference_1';
    $this->createNodeEntityReferenceView($view_name, $display_name);

    // Ensure the view can be initialized.
    $view = views_get_view($view_name);
    $this->assertTrue($view, t('The view is loaded: @view_name', array('@view_name' => $view_name)));
    $this->assertTrue(isset($view->display[$display_name]), t('The view display is loaded: @view_display', array('@view_display' => "$view_name:$display_name")));
    $this->assertTrue($view->access($display_name), t('The view display has access: @view_display ', array('@view_display' => "$view_name:$display_name")));

    $type_referenced = $this->drupalCreateContentType();

    $field_name = 'field_' . $type_referenced->type;
    $field = array(
      'field_name' => $field_name,
      'settings' => array(
        'handler' => 'views',
        'target_type' => 'node',
        'handler_settings' => array(
          'view' => array(
            'view_name' => $view_name,
            'display_name' => $display_name,
            'args' => array(),
          ),
          'behaviors' => array(
            'views-select-list' => array(
              'status' => 0,
            ),
          ),
        ),
      ),
    );
    $field_instance = array(
      'field_name' => $field_name,
      'bundle' => $this->referencingContentType,
    );

    $this->createEntityReferenceFieldForNode($field, $field_instance);

    // Get a selection handler for this field.
    $handler = entityreference_get_selection_handler($field, $field_instance);
    $handler_class = get_class($handler);
    $this->assertEqual('EntityReference_SelectionHandler_Views', $handler_class, t('@handler_class is EntityReference_SelectionHandler_Views is used for taxonomy reference field: @field_name', array(
      '@field_name' => $field_name,
      '@handler_class' => $handler_class,
    )));

    $result = $handler->getReferencableEntities();
    $this->assertFalse($result, t('There are no nodes to reference.'));

    // Add 3 referenced nodes.
    $this->drupalCreateNode(array('type' => $type_referenced->type));
    $this->drupalCreateNode(array('type' => $type_referenced->type));
    $this->drupalCreateNode(array('type' => $type_referenced->type));

    $result = $handler->getReferencableEntities();
    $count = (int) (!empty($result[$type_referenced->type])) ? count($result[$type_referenced->type]) : 0;
    $this->assertIdentical($count, 3, t('There are @count of 3 referencable nodes.', array('@count' => $count)));
  }

  /**
   * Helper to creates users for this test.
   */
  protected function createUsers() {
    $this->unprivilegedUser = $this->drupalCreateUser();

    $permissions[] = 'access content';
    $permissions[] = 'administer site configuration';
    $permissions[] = 'administer content types';
    $permissions[] = 'administer nodes';
    $permissions[] = 'bypass node access';
    $permissions[] = 'administer taxonomy';
    $permissions[] = 'administer users';

    // Create an admin user and log in.
    $this->adminUser = $this->drupalCreateUser($permissions);
  }

  /**
   * Create an Entity Reference Views view for node list.
   */
  protected function createNodeEntityReferenceView($view_name = 'test_entityreference_select_node', $display_name = 'entityreference_1') {
    $view = new view();
    $view->name = $view_name;
    $view->description = '';
    $view->tag = 'default';
    $view->base_table = 'node';
    $view->human_name = $view_name;
    $view->core = 7;
    $view->api_version = '3.0';
    $view->disabled = FALSE;

    /* Display: Master */
    $handler = $view->new_display('default', 'Master', 'default');
    $handler->display->display_options['use_more_always'] = FALSE;
    $handler->display->display_options['access']['type'] = 'perm';
    $handler->display->display_options['cache']['type'] = 'none';
    $handler->display->display_options['query']['type'] = 'views_query';
    $handler->display->display_options['exposed_form']['type'] = 'basic';
    $handler->display->display_options['pager']['type'] = 'full';
    $handler->display->display_options['style_plugin'] = 'default';
    $handler->display->display_options['row_plugin'] = 'fields';
    /* Field: Content: Title */
    $handler->display->display_options['fields']['title']['id'] = 'title';
    $handler->display->display_options['fields']['title']['table'] = 'node';
    $handler->display->display_options['fields']['title']['field'] = 'title';
    $handler->display->display_options['fields']['title']['label'] = '';
    $handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE;
    $handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE;

    /* Display: Entity Reference */
    $handler = $view->new_display('entityreference', 'Entity Reference', $display_name);
    $handler->display->display_options['defaults']['title'] = FALSE;
    $handler->display->display_options['pager']['type'] = 'some';
    $handler->display->display_options['defaults']['style_plugin'] = FALSE;
    $handler->display->display_options['style_plugin'] = 'entityreference_style';
    $handler->display->display_options['style_options']['search_fields'] = array('title' => 'title');
    $handler->display->display_options['defaults']['style_options'] = FALSE;
    $handler->display->display_options['defaults']['row_plugin'] = FALSE;
    $handler->display->display_options['row_plugin'] = 'entityreference_fields';
    $handler->display->display_options['defaults']['row_options'] = FALSE;

    $view->save();
  }

  /**
   * Create an Entity Reference Views view for term list.
   *
   * @param string $view_name
   *   View machine name.
   * @param string $display_name
   *   View display name.
   */
  protected function createTermEntityReferenceView($view_name = 'test_entityreference_select_term', $display_name = 'entityreference_1') {
    $view = new view();
    $view->name = $view_name;
    $view->description = '';
    $view->tag = 'default';
    $view->base_table = 'taxonomy_term_data';
    $view->human_name = $view_name;
    $view->core = 7;
    $view->api_version = '3.0';
    $view->disabled = FALSE;

    /* Display: Master */
    $handler = $view->new_display('default', 'Master', 'default');
    $handler->display->display_options['use_more_always'] = FALSE;
    $handler->display->display_options['access']['type'] = 'perm';
    $handler->display->display_options['cache']['type'] = 'none';
    $handler->display->display_options['query']['type'] = 'views_query';
    $handler->display->display_options['exposed_form']['type'] = 'basic';
    $handler->display->display_options['pager']['type'] = 'full';
    $handler->display->display_options['style_plugin'] = 'default';
    $handler->display->display_options['row_plugin'] = 'fields';
    /* Field: Taxonomy term: Name */
    $handler->display->display_options['fields']['name']['id'] = 'name';
    $handler->display->display_options['fields']['name']['table'] = 'taxonomy_term_data';
    $handler->display->display_options['fields']['name']['field'] = 'name';
    $handler->display->display_options['fields']['name']['label'] = '';
    $handler->display->display_options['fields']['name']['alter']['word_boundary'] = FALSE;
    $handler->display->display_options['fields']['name']['alter']['ellipsis'] = FALSE;
    $handler->display->display_options['fields']['name']['element_label_colon'] = FALSE;

    /* Display: Entity Reference */
    $handler = $view->new_display('entityreference', 'Entity Reference', $display_name);
    $handler->display->display_options['defaults']['title'] = FALSE;
    $handler->display->display_options['pager']['type'] = 'some';
    $handler->display->display_options['defaults']['style_plugin'] = FALSE;
    $handler->display->display_options['style_plugin'] = 'entityreference_style';
    $handler->display->display_options['style_options']['search_fields'] = array('name' => 'name');
    $handler->display->display_options['defaults']['style_options'] = FALSE;
    $handler->display->display_options['defaults']['row_plugin'] = FALSE;
    $handler->display->display_options['row_plugin'] = 'entityreference_fields';
    $handler->display->display_options['defaults']['row_options'] = FALSE;

    $view->save();
  }

  /**
   * Helper method to create a base field and field instance.
   *
   * @param array $field
   *   The field to be created.
   * @param array $field_instance
   *   The field instance to be created.
   */
  protected function createEntityReferenceFieldForNode(array &$field, array &$field_instance) {
    // Add the common settings.
    $field += array(
      'type' => 'entityreference',
      'module' => 'entityreference',
      'translatable' => 0,
      'entity_types' => array('node'),
    );
    field_create_field($field);

    // Add the common settings.
    $field_instance += array(
      'label' => 'Entity Reference Field',
      'entity_type' => 'node',
      'settings' => array(),
      'required' => FALSE,
      'widget' => array(
        'module' => 'options',
        'type' => 'options_select',
      ),
    );
    field_create_instance($field_instance);
  }

  /**
   * Creates a custom vocabulary.
   *
   * @return string
   *   Created vocabulary's machine name.
   */
  protected function createVocabulary() {
    // Find a non-existent random type name.
    $machine_names = taxonomy_vocabulary_get_names();
    do {
      $name = strtolower($this->randomName(8));
    } while (isset($machine_names[$name]));

    // Create a vocabulary.
    $vocabulary = new stdClass();
    $vocabulary->name = $name;
    $vocabulary->type = $name;
    $vocabulary->machine_name = $name;
    $saved_status = taxonomy_vocabulary_save($vocabulary);

    $this->assertEqual($saved_status, SAVED_NEW, t('Created vocabulary %type.', array('%type' => $name)));

    return $name;
  }

  /**
   * Creates a taxonomy term based on default settings.
   *
   * @param array $settings
   *   An associative array of settings to change from the defaults, keys are
   *   term properties, for example 'name' => 'Hello, world!'.
   *
   * @return object
   *   Created term object.
   */
  protected function createTerm(array $settings = array()) {
    // Populate defaults array.
    $settings += array(
      'name' => $this->randomName(8),
      'vid' => 1,
    );

    $term = (object) $settings;
    taxonomy_term_save($term);

    return $term;
  }

}
