Objectives

Division + Sponsor

These are the new classes for Division & Sponsor:

Division.java

package models;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.OneToMany;

import play.db.jpa.Model;

@Entity
public class Division extends Model
{
  public String name;

  @OneToMany(cascade=CascadeType.ALL)
  public List<Club> members;

  public Division(String name)
  {
    this.name = name;
    members = new ArrayList<Club>();
  } 

  public void addClub(Club club)
  {
    members.add(club);
  }

  public String toString()
  {
    return name;
  }

  public static Division findByName(String name)
  {
    return find("name", name).first();
  }
}

Sponsor.java

package models;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

import play.db.jpa.Model;

@Entity
public class Sponsor extends Model
{
  public String name;

  @ManyToMany (mappedBy="sponsors")
  public List<Club> support;

  public Sponsor(String name)
  {
    this.name = name;
    support = new ArrayList<Club>();
  }

  public void addSuport(Club club)
  {
    support.add(club);
  }

  public String toString()
  {
    return name;
  }
}

Club.java


  //...
  @ManyToMany
  public List<Sponsor> sponsors;
  //...

  public Club(String name)
  {
    this.name = name;
    this.players = new ArrayList<Player>();
    this.sponsors = new ArrayList<Sponsor>();
  }

  public void addSponsor(Sponsor company)
  {
    sponsors.add(company);  
  }

If you are still using git, Commit these with the message "Division + Sponsor + modification to Club"

Tests

We can significantly simplify aspects of the testing if we invest some time in setting up test objects in yaml first.

Open 'test/data.yaml'. Note this is a different version of the yaml file from the one in conf. Replace its contents with the following:

Club(dunmore):
    name: dunmore

Club(tramore):
    name: tramore

Club(fenor):
    name: fenor

Player(jim):
    name: jim
    club: dunmore

Player(mary):
    name: mary
    club: dunmore

Player(sam):
    name: sam
    club: tramore

Player(john):
    name: john
    club: tramore

Player(mike):
    name: mike
    club: fenor

Player(linda):
    name: linda
    club: fenor    

Division(senior):
    name: senior
    members:
            - tramore
            - dunmore

Division(junior):
    name: junior
    members:
            - fenor

Sponsor(newsagent):
    name: newsagent

Sponsor(pub):
    name: pub 

Now bring in a new test class that will exercise this model:

import org.junit.*;

import java.util.*;

import play.Logger;
import play.test.*;
import models.*;

public class ComprehensiveTest extends UnitTest
{
  public static void loadSponsorships()
  {
    Club    tramore   = Club.find("byName", "tramore").first();
    Club    dunmore   = Club.find("byName", "dunmore").first();
    Sponsor newsagent = Sponsor.find("byName", "newsagent").first();

    tramore.addSponsor(newsagent);
    dunmore.addSponsor(newsagent);

    newsagent.addSuport(tramore);
    newsagent.addSuport(dunmore);

    tramore.save();
    dunmore.save();
    newsagent.save();
  }

  @Before
  public void setup()
  {
    Fixtures.loadModels("data.yml");
    loadSponsorships();
  }

  @After
  public void teardown()
  {
    Fixtures.deleteAllModels();
  }

  @Test
  public void testPlayerClubLong()
  {
    Player jim;
    Club   dunmore;

    jim = Player.find("byName", "jim").first();
    assertNotNull(jim);
    assertEquals(jim.name, "jim");

    dunmore = jim.club;
    assertEquals("dunmore", dunmore.name);

    dunmore = Club.find("byName", "dunmore").first();
    assertNotNull(dunmore);
    assertEquals("dunmore", dunmore.name);    
    assertEquals(2, dunmore.players.size());

    Player p1 = dunmore.players.get(0);
    assertTrue (p1.name.equals("jim") || p1.name.equals("mary"));
    Player p2 = dunmore.players.get(1);
    assertTrue (p2.name.equals("jim") || p2.name.equals("mary"));  
  }

  @Test
  public void testDivisionClubLong()
  {
    Division senior = Division.find("byName", "senior").first();
    assertNotNull(senior);
    assertEquals(2, senior.members.size());

    Club c1 = senior.members.get(0);
    Club c2  = senior.members.get(1);

    assertTrue (c1.name.equals("tramore") || c1.name.equals("dunmore"));      
    assertTrue (c2.name.equals("tramore") || c2.name.equals("dunmore"));          
  }


  //----------------------------------------------------------------------
  @Test
  public void testPlayerClub()
  {
    Club   dunmore = Club.find("byName", "dunmore").first();
    Player jim     = Player.find("byName", "jim").first(); 
    Player mary    = Player.find("byName", "mary").first(); 
    assertNotNull(mary);

    assertTrue (dunmore.players.contains(jim));
    assertTrue (dunmore.players.contains(mary)); 
  }

  @Test
  public void testDivisionClub()
  {
    Division senior  = Division.find("byName", "senior").first();
    Club     dunmore = Club.find("byName", "dunmore").first();
    Club     tramore = Club.find("byName", "tramore").first();

    assertTrue (senior.members.contains(dunmore));
    assertTrue (senior.members.contains(tramore));
  }

  @Test
  public void testClubSponsorShort()
  {
    Sponsor  newsagent = Sponsor.find("byName", "newsagent").first();
    Club     dunmore   = Club.find("byName", "dunmore").first();
    Club     tramore   = Club.find("byName", "tramore").first();

    assertTrue(newsagent.support.contains(dunmore));
    assertTrue(newsagent.support.contains(tramore));

    assertTrue(dunmore.sponsors.contains(newsagent));
    assertTrue(tramore.sponsors.contains(newsagent));
  }

  @Test
  public void testEditPlayerClub()
  {
    Club   dunmore = Club.find("byName", "dunmore").first();
    Player jim     = Player.find("byName", "jim").first(); 
    Player mary    = Player.find("byName", "mary").first();

    dunmore.players.remove(mary);
    mary.delete();
    dunmore.save();

    assertEquals (dunmore.players.size(), 1);
    assertTrue (dunmore.players.contains(jim));

    assertEquals(0, Player.find("byName", "mary").fetch().size());

    Player sara     = new Player("sara");
    dunmore.addPlayer(sara);
    dunmore.save();
    assertEquals (dunmore.players.size(), 2);    
  }

  @Test
  public void testEditClubSponsor()
  {
    Sponsor  newsagent = Sponsor.find("byName", "newsagent").first();
    Club     dunmore   = Club.find("byName", "dunmore").first();

    assertEquals(2, newsagent.support.size());  

    newsagent.support.remove(dunmore);
    dunmore.sponsors.remove(newsagent);

    newsagent.save();
    dunmore.save();

    assertEquals(1, newsagent.support.size());  
  }
}

Run the app in test mode, and run this new test suite. All of these tests should run.

Commit these changes with the message 'Comprehensive tests for new model objects'

Controllers/View

Incorporate all of these new artifacts:

PlayersController

package controllers;

import java.util.List;

import models.Player;
import play.mvc.Controller;

public class PlayersController extends Controller
{      
  public static void index()
  {
    List<Player> players = Player.findAll();
    render (players);
  }
}

ClubsController

package controllers;

import java.util.List;

import models.Club;
import play.mvc.Controller;

public class ClubsController extends Controller
{      
  public static void index()
  {
    List<Club> clubs = Club.findAll();
    render (clubs);
  }
}

SponsorsController

package controllers;

import java.util.List;

import models.Sponsor;
import play.mvc.Controller;

public class SponsorsController extends Controller
{      
  public static void index()
  {
    List<Sponsor> sponsors = Sponsor.findAll();
    render (sponsors);
  }
}

DivisionController

package controllers;

import java.util.List;

import models.Division;
import play.mvc.Controller;

public class DivisionController extends Controller
{      
  public static void index()
  {
    List<Division> divisions = Division.findAll();

    render (divisions);
  }
}

You will also need the corresponding views:

views/PlayersController

#{extends 'main.html' /}
#{set title:'Home' /}

#{include 'nav/open.html' /}
              <li>                <a href="/divisions">     Divisions </a></li>
              <li>                <a href="/clubs">         Clubs     </a></li>
              <li class="active"> <a href="/players">       Players   </a></li>                 
              <li>                <a href="/sponsors">      Sponsors  </a></li>
#{include 'nav/close.html' /}

    <div class="container">
      <div class="page-header">
        <h1>Players</h1>
      </div>
      <div class="row">
        <div class="span8">
          <div class="well">
            <table class="table">
              <thead>
                <tr>
                  <th>Player</th>
                  <th>
                  </th>
                  <th>
                  </th>
                </tr>
              </thead>
              <tbody>
              #{list items:players, as:'player'}
                <tr>
                  <td>${player.name}</td>
                  <td></td>
                  <td></td>
                </tr>
              #{/list}
              </tbody>
            </table>
          </div>
        </div>
      </div> 
    </div>

views/ClubsController

#{extends 'main.html' /}
#{set title:'Home' /}

#{include 'nav/open.html' /}
              <li>                <a href="/divisions">     Divisions </a></li>
              <li class="active"> <a href="/clubs">         Clubs     </a></li>
              <li>                <a href="/players">       Players   </a></li>                 
              <li>                <a href="/sponsors">      Sponsors  </a></li>
#{include 'nav/close.html' /}

    <div class="container">
      <div class="page-header">
        <h1>Clubs</h1>
      </div>
      <div class="row">
        <div class="span8">
          <div class="well">
            <table class="table">
              <thead>
                <tr>
                  <th>Club</th>
                  <th>
                  </th>
                  <th>
                  </th>
                </tr>
              </thead>
              <tbody>
              #{list items:clubs, as:'club'}
                <tr>
                  <td>${club.name}</td>
                  <td></td>
                  <td></td>
                </tr>
              #{/list}
              </tbody>
            </table>
          </div>
        </div>
      </div> 
    </div>

views/SponsorsController

#{extends 'main.html' /}
#{set title:'Home' /}

#{include 'nav/open.html' /}
              <li>                <a href="/divisions">     Divisions </a></li>
              <li>                <a href="/clubs">         Clubs     </a></li>
              <li>                <a href="/players">       Players   </a></li>                 
              <li class="active"> <a href="/sponsors">      Sponsors  </a></li>
#{include 'nav/close.html' /}

    <div class="container">
      <div class="page-header">
        <h1>Sponsors</h1>
      </div>
      <div class="row">
        <div class="span8">
          <div class="well">
            <table class="table">
              <thead>
                <tr>
                  <th>Sponsor</th>
                  <th>
                  </th>
                  <th>
                  </th>
                </tr>
              </thead>
              <tbody>
              #{list items:sponsors, as:'sponsor'}
                <tr>
                  <td>${sponsor.name}</td>
                  <td></td>
                  <td></td>
                </tr>
              #{/list}
              </tbody>
            </table>
          </div>
        </div>
      </div> 
    </div>

views/DivisionsController

#{extends 'main.html' /}
#{set title:'Home' /}

#{include 'nav/open.html' /}
              <li class="active"> <a href="/divisions">     Divisions </a></li>
              <li>                <a href="/clubs">         Clubs     </a></li>
              <li>                <a href="/players">       Players   </a></li>                 
              <li>                <a href="/sponsors">      Sponsors  </a></li>
#{include 'nav/close.html' /}

    <div class="container">
      <div class="page-header">
        <h1>Divisions</h1>
      </div>
      <div class="row">
        <div class="span8">
          <div class="well">
            <table class="table">
              <thead>
                <tr>
                  <th>Division</th>
                  <th>
                  </th>
                  <th>
                  </th>
                </tr>
              </thead>
              <tbody>
              #{list items:divisions, as:'division'}
                <tr>
                  <td>${division.name}</td>
                  <td></td>
                  <td></td>
                </tr>
              #{/list}
              </tbody>
            </table>
          </div>
        </div>
      </div> 
    </div>

These templates need a folder called 'nav' to be created in 'views' - and it must contain:

open.html

<nav class="navbar navbar-default" role="navigation">
  <div class="collapse navbar-collapse">
    <ul class="nav navbar-nav">

close.html

    </ul>
  </div>
</nav>

Now incorporate the following routes:

# Home page
GET     /                                       DivisionController.index
GET     /divisions                              DivisionController.index
GET     /clubs                                  ClubsController.index
GET     /players                                PlayersController.index
GET     /sponsors                               SponsorsController.index

In addition, as we are powering up the ui, we will need to make sure data source in application.conf is configured:

db=mem

Save everything and run (not in test mode). Browse to

It views will be largely bank and unformatted.

Commit these changes, nevertheless, using the string "Controllers/Views for all models"

Test Data + Formatting

There is a data.yaml file in your test folder. Copy this to the conf folder (there will now me two files of this name).

Create a class called 'BootStrap.java' in you 'app' folder, and replace its content with this source here:

BootStrap.java

import models.Division;
import play.jobs.*;
import play.test.*;

@OnApplicationStart
public class Bootstrap extends Job<Object> 
{ 
  public void doJob()
  {
    if (Division.count() == 0)
    {
      Fixtures.loadModels("data.yml");
    }
  }
}

Run the app again, and you should start to see some data.

The views are constructed expecting to have twitter bootstrap loaded. We will do this now.

Replace your 'views/main.html' with the following:

<!DOCTYPE html>
  <html>
    <head>
    <title>#{get 'title' /}</title>
    <meta charset="${_response_encoding}">
    <link rel="stylesheet" href="@{'/public/bootstrap/css/bootstrap.min.css'}">
    <script src="@{'/public/javascripts/jquery-1.6.4.min.js'}"></script>
    <script src="@{'/public/bootstrap/js/bootstrap.min.js'}"></script>
    <link rel="shortcut icon" type="image/png" href="@{'/public/images/favicon.png'}">
    <style>
      body 
      {
        padding-top: 60px;
      }
    </style>
  </head>
  <body>
    #{doLayout /}
  </body>
</html>

Note that we need the bootstrap files in public for this to work. Locate these files and copy them in. Bootstrap has been updated to version 3 since you may have used it last. Locate the v3 version from the web and incorporate.

Reload the app - you should have the menus/views as expected.

Commit this with the message 'Test Data + bootstrap files'

Showing Division/Club/Player Relationships

Currently UI for the model is read only - and we can only see each model in isolation (we cant see relationships). We would like to make the relationships visible.

Replace the <table> element of the following views with this version:

views/PlayersController/index.html

           <table class="table">
              <thead>
                <tr>
                  <th>Player</th>
                  <th>Club  </th>
                </tr>
              </thead>
              <tbody>
              #{list items:players, as:'player'}
                <tr>
                  <td>${player.name}</td>
                  <td>${player.club.name}</td>
                </tr>
              #{/list}
              </tbody>
            </table>

views/ClubsController/index.html

            <table class="table">
              <thead>
                <tr>
                  <th>Club</th>
                </tr>
              </thead>
              <tbody>
              #{list items:clubs, as:'club'}
                <tr>
                  <td>${club.name}</td>
                  <td>
                    <table class="table">
                      <tr>
                      #{list items:club.players, as:'player'}
                        <td>${player.name}</td> </tr>
                      #{/list}
                      </tr>
                    </table>
                  </td>                  
                </tr>
              #{/list}
              </tbody>
            </table>

views/DivisionsController/index.html

            <table class="table">
              <thead>
                <tr>
                  <th>Division</th>
                  <th>Club </th>
                </tr>
              </thead>
              <tbody>
                #{list items:divisions, as:'division'}
                <tr>
                  <td>${division.name}</td>
                  <td>
                    <table class="table">
                      <tr>
                      #{list items:division.members, as:'club'}
                        <td>${club.name}</td> </tr>
                      #{/list}
                      </tr>
                    </table>
                  </td>
                </tr>
                #{/list}
              </tbody

See if you can make sense of the above templates. Save everything and reload. You should be able to see what players belong to which clubs, and also what divisions the clubs are in.

Commit these changes with a message 'show Division/Club/Player relationships'

Delete Player Feature

Introduce the following method into the controllers/PlayersController:

  public static void delete(Long id)
  {
    Player player = Player.findById(id);
    if (player != null)
    {
      if (player.club != null)
      {
        player.club.removePlayer(player);
        player.club.save();
      }
      player.delete();
    }
    index();
  }

Which requires this method in models/Club.java

  public void removePlayer(Player player)
  {
    players.remove(player);
  }

Now change the loop in the 'views/PlayersController/index.html' file:

              #{list items:players, as:'player'}
                <tr>
                  <td>${player.name}</td>
                  <td>${player.club.name}</td>
                  <td> <a class="btn btn-danger btn-mini" href="@{PlayersController.delete(player.id)}">Delete</a> </td>
                </tr>
              #{/list}

(just one line changed in the above).

Run the app - players now have a delete button, which should work as expected.

Commit this modification with a 'Delete Player Feature' commit message.

New Player Feature

Create the following new methods in PlayersController:

  public static void newPlayer()
  {
    List<Club> clubs = Club.findAll();
    render(clubs);
  }

  public static void createPlayer(String name, String club)
  {
    Logger.info("Name: " + name + ": Club: " + club);

    Player player = new Player (name);
    Club theClub = Club.findByName(club);
    if (theClub != null)
    {
      theClub.addPlayer(player);
      theClub.save();
    }
    else
    {
      player.save();
    }
    index();

These imports will be needed:

import java.util.List;
import models.Club;
import play.Logger;

In PlayersController/index.html, add this at the end inside the closing <div>

      </div> 
      <a class="btn btn-primary" href="@{PlayersController.newPlayer()}">New Player</a> 
    </div>

Now create a new html file in the views/PlayersController folder called 'newplayer.html'

#{extends 'main.html' /}
#{set title:'Add Player' /}

#{include 'nav/open.html' /}

#{include 'nav/close.html' /}


<div class="container">
  <div class="page-header">
    <h1>Create new Player</h1>
  </div>
  <div class="alert alert-info hidden-phone">
    <a class="close" data-dismiss="alert">x</a>
    <b>Enter name and select club of new player</b> 
  </div>

  <form action="@{PlayersController.createPlayer()}" method="POST">

  <div class="well">
    <div class="row">
      <div class="span4">
        <div class="control-group">
          <label class="control-label">Player name</label>
          <div class="controls">
            <input name="name" type="text" class="input-medium input-block-level"> 
          </div>
        </div>
      </div>
      <div class="span7">
        <div class="control-group">
          <label class="control-label">Club</label>
          <div class="controls">
            <select name="club">
              #{list items:clubs, as:'club'}
                <option>${club.name}</option>
              #{/list}
            </select>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div class="span2">     
    <button class="btn btn-block">Save</button> 
  </div>

  </form>

  <div class="span2">
    <a href="@{PlayersController.index()}" class="btn btn-block">Cancel</a> 
  </div>

</div>

Save everything - and verify that you can now add players using the app.

Commit all changes with the message 'New Player Feature'

Create and Delete Clubs

A new version of ClubsController which has several new methods:

package controllers;

import java.util.List;

import models.Club;
import models.Division;
import play.Logger;
import play.mvc.Controller;

public class ClubsController extends Controller
{      
  public static void index()
  {
    List<Club> clubs = Club.findAll();
    render (clubs);
  }

  public static void newClub()
  {
    List<Division> divisions = Division.findAll();
    render(divisions);
  }


  public static void delete(Long id)
  {
    Club club = Club.findById(id);
    if (club != null)
    {
      Logger.info("Trying to delete " + club.name);
      List<Division> divisions = Division.findAll();
      for (Division division : divisions)
      {
        if (division.members.contains(club))
        {
          division.members.remove(club);
          division.save();
          Logger.info ("removing club from division");
        }
      }
      club.delete();
    }
    index();
  }  

  public static void createClub (String name, String division)
  {    
    Logger.info("name: " + name + "Division: " + division);

    Club club = new Club(name);
    club.save();

    Division theDivision = Division.findByName(division);
    if (theDivision != null)
    {
      theDivision.addClub(club);
      theDivision.save();
    }
    index();
  }
}
~~~~

A new version of the ClubsController/index.html:

~~~html
#{extends 'main.html' /}
#{set title:'Home' /}

#{include 'nav/open.html' /}
              <li>                <a href="/divisions">     Divisions </a></li>
              <li class="active"> <a href="/clubs">         Clubs     </a></li>
              <li>                <a href="/players">       Players   </a></li>                 
              <li>                <a href="/sponsors">      Sponsors  </a></li>
#{include 'nav/close.html' /}

    <div class="container">
      <div class="page-header">
        <h1>Clubs</h1>
      </div>
      <div class="row">
        <div class="span8">
          <div class="well">
            <table class="table">
              <thead>
                <tr>
                  <th>Club</th>
                  <th>Players</th>
                </tr>
              </thead>
              <tbody>
              #{list items:clubs, as:'club'}
                <tr>
                  <td>${club.name}</td>
                  <td>
                    <table class="table">
                      <tr>
                      #{list items:club.players, as:'player'}
                        <td>${player.name}</td> </tr>
                      #{/list}
                      </tr>
                    </table>
                  </td>    
                  <td> <a class="btn btn-danger btn-mini" href="@{ClubsController.delete(club.id)}">Delete</a> </td>
                </tr>
              #{/list}
              </tbody>
            </table>
          </div>
        </div>
      </div> 
      <a class="btn btn-primary" href="@{ClubsController.newClub()}">New Club</a> 
    </div>

and a new view - ClubsController/newclub.html:

#{extends 'main.html' /}
#{set title:'Add Player' /}

#{include 'nav/open.html' /}

#{include 'nav/close.html' /}


<div class="container">
  <div class="page-header">
    <h1>Create new Club</h1>
  </div>
  <div class="alert alert-info hidden-phone">
    <a class="close" data-dismiss="alert">x</a>
    <b>Enter name of club</b> 
  </div>

  <form action="@{ClubsController.createClub()}" method="POST">

  <div class="well">
    <div class="row">
      <div class="span4">
        <div class="control-group">
          <label class="control-label">Club name</label>
          <div class="controls">
            <input name="name" type="text" class="input-medium input-block-level"> 
          </div>
        </div>
      </div>
      <div class="span7">
        <div class="control-group">
          <label class="control-label">Division</label>
          <div class="controls">
            <select name="division">
              #{list items:divisions, as:'division'}
                <option>${division.name}</option>
              #{/list}
            </select>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div class="span2">     
    <button class="btn btn-block">Save</button> 
  </div>

  </form>

  <div class="span2">
    <a href="@{ClubsController.index()}" class="btn btn-block">Cancel</a> 
  </div>

</div>

Verify that you can now add a club using the app.

Commit these changes with the message: "Create and Delete Clubs feature"

Edit Player Feature

Introduce the following two methods into the PlayersController:

  public static void changePlayer(Long id, String name, Long club)
  {
    Player player = Player.findById(id);
    if (player != null)
    {
      player.name = name;
      Club theClub = Club.findById(club);
      player.club = theClub;
      player.save();
    }
    index();
  }

  public static void editPlayer(Long id)
  {
    Player player = Player.findById(id);
    List<Club> clubs = Club.findAll();
    Integer clubIndex = clubs.indexOf(player.club);
    clubIndex++;
    render(player, clubs, clubIndex);
  }

Incorporate the following new view in views/PlayersController/editplayer.html

#{extends 'main.html' /}
#{set title:'Add Player' /}

#{include 'nav/open.html' /}

#{include 'nav/close.html' /}


<div class="container">
  <div class="page-header">
    <h1>Edit Player</h1>
  </div>
  <div class="alert alert-info hidden-phone">
    <a class="close" data-dismiss="alert">x</a>
    <b>Change Player name or Club affiliation</b> 
  </div>


  #{form @PlayersController.changePlayer(player.id), method:'post'}

    <div class="well">
      <div class="row">
        <div class="span4">
          <div class="control-group">
            <label class="control-label">Player name</label>
            <div class="controls">
              <input name="name" type="text" class="input-medium input-block-level" value="${player.name}"> 
            </div>
          </div>
        </div>
        <div class="span7">
          <div class="control-group">
            <label class="control-label">Club</label>
            <div class="controls">
              #{select 'club', items:clubs, value:clubIndex, valueProperty:'id'}
              #{/select} 
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="span2">     
      <button class="btn btn-block">Save</button> 
    </div>

  #{/form}

  <div class="span2">
    <a href="@{PlayersController.index()}" class="btn btn-block">Cancel</a> 
  </div>

</div>

In views/PlayersController/index.html add a new 'edit' button after the 'delete' button:

                 <td> <a class="btn btn-info btn-mini" href="@{PlayersController.editPlayer(player.id)}">Edit</a> </td>

You should now be able to edit the and change player details.

Commit these changes as "Edit Player Feature"

Exercises

Solution

Completed version:

Exploring the Database

Edit the file ComprehensiveTest.java test case, and comment our all of the @Test annotations except one (say the first one). This will remove all tests from the test runner.

Also, comment out the call to 'deleteAllModels()' from tearDown()

  @After
  public void teardown()
  {
    //Fixtures.deleteAllModels();
  }

Restart the app in test mode, and run just the comprehensive test (not the others).

While still in test mode, browse to:

You should be able to see a fully populate UI + Database. You may be interested in looking at each of the tables in turn on the database to get a feel for the mapping performed by JPA. A useful exercise would be to use pen & paper to draw the all the tables and their contents. Use ER mapping notation to show the table relationships. This could prove invaluable in debugging relationships you may be designing for your assignments.

Be sure to comment the test annotation back in when you finish.

Divisions & Sponsors

The divisions and sponsors controllers/view are currently read-only. I.ee it is not possible to add or edit the entities. Using the Players and CLubs as examples, bring in the ability create/edit divisions and sponsors.

New Bootstrap template site

If you have made the switch to bootstrap 3 - then you might be interested in this new site with free bootstrap templates here:

It includes some very useful Full Site Templates:

See this demo here:

In particular, try the last link on a mobile device. If you dont have one connected, browse to that site using the Android Simulator.