Implementation Walk-Through

This subsection provides the code for a sample implementation of the Skills Matrix. It includes the controller, the page, and controller test cases.

Skills Matrix Controller

Listing 6.20 contains a sample implementation of the Skills Matrix controller class. The controller has four variables, each with a getter method for access by the Visualforce page. The selectedContactId variable contains the unique identifier of the contact selected for editing or viewing. isEditable is a flag used by the page to enable or disable the Save button and to determine whether to render skills as text fields or editable drop-down lists. The selectedContact variable contains several fields from the Contact object needed throughout the controller, queried using the selectedContactId. The selectedSkills list contains the skill types and ratings to be displayed and edited in the user interface, and this same list is used to update the database upon a save action.

The controller has two actions: save and refresh. The save action applies the changes from the drop-down lists of skill ratings by upserting them into the database. The refresh action uses the unique identifier of the currently selected contact (selectedContactId) to query the database for Skill records. It compares them against the complete list of skill types via the database metadata call getPicklistValues. Finally, it updates the isEditable variable based on whether the current user is privileged or is associated with the currently viewed contact.

Several helper methods are in the controller. addError and addInfo are shortcuts for adding notifications to the page, displayed using the pageMessages component. The getCurrentUserContact method queries the Contact record corresponding to the current user. The isManager method returns true if the user is privileged, enabling the user to edit the skills of any contact.

Listing 6.20 Skills Matrix Controller


public class SkillsMatrixController {
  public String selectedContactId { get; set; }
  public Boolean isEditable { get; private set; }
  public Contact selectedContact { get; private set; }
  public List<Skill__c> selectedSkills { get; private set; }
  public List<SelectOption> getContactOptions() {
    List<SelectOption> options = new List<SelectOption>();
      options.add(new SelectOption(
        '', '-- Select Contact --'));
    List<Contact> contacts = [ SELECT Id, Name
      FROM Contact ORDER BY LastName ];
    for (Contact contact : contacts) {
      options.add(new SelectOption(contact.Id,
        contact.Name));
    }
    return options;
  }
  public PageReference refresh() {
    if (selectedContactId == null) {
      addError('Select a contact'),
      return null;
    }
    selectedContact = [ SELECT Id, Name,
      User__r.UserRoleId,
      User__r.ProfileId,
      (SELECT Type__c, Rating__c, LastModifiedDate
        FROM Skills__r ORDER BY Rating__c DESC)
      FROM Contact
      WHERE Id = :selectedContactId
      LIMIT 1 ];
    Set<String> skillTypes = new Set<String>();
    selectedSkills = new List<Skill__c>();
    for (Skill__c skill : selectedContact.Skills__r) {
      skillTypes.add(skill.Type__c);
      selectedSkills.add(skill);
    }
    Schema.DescribeFieldResult field = Skill__c.Type__c.getDescribe();
    String picklistValue = null;
    for (Schema.PicklistEntry entry : field.getPicklistValues()) {
      picklistValue = entry.getLabel();
      if (!skillTypes.contains(picklistValue)) {
        selectedSkills.add(
          new Skill__c(Contact__c = selectedContact.Id,
            Type__c = picklistValue));
      }
    }
    if (isManager()) {
      isEditable = true;
    } else {
      Contact userContact = getCurrentUserContact();
      isEditable =
        selectedContact != null && userContact != null
        && selectedContact.Id == userContact.Id;
    }
    return null;
  }
  private void addError(String msg) {
    ApexPages.addMessage(new ApexPages.Message(
      ApexPages.Severity.ERROR, msg));
  }
  private void addInfo(String msg) {
    ApexPages.addMessage(new ApexPages.Message(
      ApexPages.Severity.INFO, msg));
  }
  public Contact getCurrentUserContact() {
    List<Contact> userContact = [ SELECT Id, Name,
      User__r.UserRoleId, User__r.ProfileId
      FROM Contact
      WHERE User__c = :UserInfo.getUserId()
      LIMIT 1 ];
    if (userContact.size() == 0) {
      addError('No contact associated with user'),
      return null;
    } else {
      return userContact.get(0);
    }
  }
  private Boolean isManager() {
    List<Profile> profiles = [ SELECT Id
      FROM Profile WHERE Name IN (
      'Project Manager', 'Vice President', 'System Administrator')
      AND Id = :UserInfo.getProfileId() LIMIT 1 ];
    return profiles.size() == 1;
  }
  public PageReference save() {
    try {
      upsert selectedSkills;
      addInfo('Changes saved'),
    } catch(DmlException e) {
      addError('Could not save changes: ' + e.getMessage());
    }
    return null;
  }
}


Skills Matrix Visualforce Page

Listing 6.21 contains sample code for the Skills Matrix Visualforce page. It uses Force.com-styled view components to achieve an appearance that resembles the native user interface. The pageBlock and pageBlockButtons components visually separate the selection of the resource from the skills data and Save button, and the sectionHeader component mimics the appearance of a native object tab.

The pageBlockTable component iterates over the list of skills, displaying them as a table using standard Force.com styling. Each row of the table includes two columns. The first column contains the skill type. The second contains two components: one for editing the skill rating and another strictly for viewing it. Only one of these components is shown at a time. They are rendered conditionally based on whether the controller has determined the data to be editable. If the skills data is editable, only the inputField component is rendered. If the current user does not have the rights to edit the ratings, only the outputField is rendered.

Listing 6.21 Skills Matrix Visualforce Page


<apex:page controller="SkillsMatrixController"
  tabStyle="Skill__c">
  <style>
  .contactLabel { padding-right: 15px; }
  .goButton { margin-left: 10px; }
  </style>
  <apex:sectionHeader title="Services Manager"
    subtitle="Skills Matrix" />
  <apex:pageMessages />
  <apex:form id="form">
  <apex:outputLabel value="Contact:" for="selectedContactId"
    styleClass="contactLabel" />
  <apex:selectList id="selectedContactId" title="Contact"
    value="{!selectedContactId}" size="1">
    <apex:selectOptions value="{!contactOptions}" />
  </apex:selectList>
  <apex:commandButton action="{!refresh}" value="Go!"
    styleClass="goButton" />
  <p />
  <apex:pageBlock title="Skills">
    <apex:pageBlockButtons>
      <apex:commandButton action="{!save}" value="Save"
        disabled="{!NOT isEditable}" />
    </apex:pageBlockButtons>
    <apex:pageBlockTable value="{!selectedSkills}" var="skill"
      rendered="{!selectedContactId != ''}">
      <apex:column value="{!skill.Type__c}" />
      <apex:column headerValue="Rating">
        <apex:outputField value="{!skill.Rating__c}"
          rendered="{!NOT isEditable}" />
        <apex:inputField value="{!skill.Rating__c}"
          rendered="{!isEditable}" />
      </apex:column>
      <apex:column value="{!skill.LastModifiedDate}" />
    </apex:pageBlockTable>
  </apex:pageBlock>
  </apex:form>
</apex:page>


Controller Tests

The test cases in Listing 6.22 achieve 96% coverage of the Skills Matrix controller. They begin with a static initializer and init method to prepare the database for the tests by adding test data. This data is not permanent. All database actions during testing are rolled back automatically upon test completion.

The test cases rely on two Contact records: Tim and Barry. To test the behavior of the Skills Matrix on existing data, Tim is given a single Skill record, whereas Barry is left without skills. For testing security, Tim’s Contact record is associated with a User record named Tim, whereas Barry’s Contact record is not mapped to a User record. Update the query for the users in the static initializer to match two usernames in your own organization.

Listing 6.22 Skills Matrix Unit Test Class


@isTest
private class TestSkillsMatrixController {
  static PageReference page;
  static SkillsMatrixController controller;
  static Contact barry, tim;
  static User barryUser, timUser;
  static {
    timUser = [ SELECT Id FROM User WHERE Name = 'Tim Barr' LIMIT 1 ];
    barryUser = [ SELECT Id FROM User WHERE Name = 'Barry Cade' LIMIT 1 ];
    init();
  }
  private static void init() {
    barry = new Contact(FirstName = 'Barry', LastName = 'Cade'),
    tim = new Contact(FirstName = 'Tim', LastName = 'Barr',
      User__c = timUser.Id);
    insert new Contact[] { barry, tim };
    Skill__c[] skills = new Skill__c[] {
      new Skill__c(Type__c = 'Java', Rating__c = '3',
        Contact__c = tim.Id) };
    insert skills;
    page = new PageReference('SkillsMatrix'),
    Test.setCurrentPage(page);
    controller = new SkillsMatrixController();
  }
  static testMethod void testAsUser() {
    System.runAs(timUser) {
      init();
      controller.selectedContactId = barry.Id;
      controller.refresh();
      System.assert(!controller.isEditable);
      controller.selectedContactId = tim.Id;
      controller.refresh();
      System.assert(controller.isEditable);
    }
  }
  static testMethod void testNoContactForUser() {
    System.runAs(barryUser) {
      init();
      controller.selectedContactId = barry.Id;
      controller.refresh();
      System.assert(ApexPages.hasMessages(ApexPages.Severity.ERROR));
    }
  }
  static testMethod void testNoSkills() {
    controller.getContactOptions();
    controller.selectedContactId = barry.Id;
    controller.refresh();
    System.assert(controller.selectedSkills.size() > 0);
    System.assert(controller.isEditable);
  }
  static testMethod void testWithSkills() {
    controller.getContactOptions();
    controller.selectedContactId = tim.Id;
    controller.refresh();
    System.assert(controller.selectedSkills.size() > 0);
    System.assert(controller.selectedSkills.get(0).Type__c == 'Java'),
  }
  static testMethod void testNoContactSelected() {
    controller.selectedContactId = null;
    PageReference ref = controller.refresh();
    System.assert(ApexPages.hasMessages());
  }
  static testMethod void testSave() {
    final String skillRating = '5 - Expert';
    controller.getContactOptions();
    controller.selectedContactId = barry.Id;
    controller.refresh();
    List<Skill__c> selectedSkills = controller.selectedSkills;
    Skill__c skill = selectedSkills.get(0);
    skill.Rating__c = skillRating;
    String skillType = skill.Type__c;
    controller.save();
    System.assert(ApexPages.hasMessages(ApexPages.Severity.INFO));
    Skill__c savedSkill = [ SELECT Rating__c FROM Skill__c
      WHERE Contact__c = :barry.Id AND
        Type__c = :skillType LIMIT 1 ];
    System.assert(savedSkill != null &&
      savedSkill.Rating__c == skillRating);
  }
}


The test methods are described here in the order in which they appear in the code:

Image testAsUserThis test uses the System.runAs method to assume the identity of Tim. Tim is assigned to a User, so when his corresponding Contact record is selected and the list of skills is refreshed, the isEditable flag should be set to true. If Barry is selected, the flag should be false.

Image testNoContactForUserSystem.runAs is used again, this time to test for an error condition. Barry’s user does not have a child Contact record, so he should receive an error when visiting the Skills Matrix. Without a mapping to the User object, the application cannot determine whether the current user has access to edit skills.

Image testNoSkillsThis test method runs as a System Administrator. It selects Barry from the contact list and refreshes, asserting that there are Skills records. These records are created from the Skill object’s Type__c field’s picklist values. Another assertion is made that the skill ratings are editable because an administrator can edit the skills of all contacts.

Image testWithSkillsThis test retrieves the skills for Tim and asserts that the Java skill is first in the list. This is because Tim already has a Skill record for Java, and existing records should be placed at the top of the user interface.

Image testNoContactSelectedThe selected contact is set to null to verify that an information message is added to the page. This message instructs the user to select a contact.

Image testSaveThis test uses the controller to rate Barry as an expert in the first skill on the skills list. It then queries the database independently to verify that the controller saved the data correctly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.231.26