FOSP For Developers Part 4: Build a custom module step 2

In step 1 of this tutorial, we began our journey down the rabbit hole of module development by first creating a module using the Module Builder tool, adding permissions and a custom database setting entry via a Bonfire Migration and creating a page in the Settings context by editing a settings controller and view.

Now comes the fun part, the public controller and view that will load the team stats and display them to the user in the public portion of the site. Here’s what our final page will look like before we submit the form:


And after



The View Controller

As I stated in the previous step, to allow users to access a public page for your module, you need to have a PHP file named to match your module name in the modules controllers folder. The Bonfire module builder created such a file for us, so let’s open it up (“bonfire/modules/statslist/controllers/statslist.php”).

Replace the __construct function with what you see here:

public function __construct()

All were doing here is calling to the parent constructor method, which sets up the basics of this controller, and loading the statlist language file we worked on in Part 1.

Now for the meat of the class. Copy the following code for the index() function replacing it if it’s already there:

public function index() 
	$settings = $this->settings_lib->find_all();


	$years = $this->leagues_model->get_all_seasons($settings['osp.league_id']);

	if ($this->input->post('submit')) 
		$team_id = ($this->input->post('team_id') ? $this->input->post('team_id') : false);
		$year = ($this->input->post('year')? $this->input->post('year') : false);

		if ($team_id !== false)
			$records = array (
				'Batting'=>$this->players_model->get_current_stats(2,$settings['osp.league_id'], $year, $team_id),
				'Pitching'=>$this->players_model->get_current_stats(1,$settings['osp.league_id'], $year, $team_id)
			Template::set('team_details',$this->teams_model->select('team_id, name, nickname, logo_file')->find($team_id));
	Template::set('teams',$this->teams_model->get_teams_array(($settings['statslist.limit_to_primary'] == 1) ? $settings['osp.league_id'] : false));

There’s a lot here, but let’s break it down.

  • First we load the site settings from the Bonfire settings_lib. Unlike how we loaded settings in the settings controller tutorial where we only loaded the sittings for the statslist module, we want other settings as well this time so we use find_all() which returns all settings from the database.
  • Next we load the Teams and Leagues models, both standard items in the companion OOTP Web Toolkit. These will give us access to function that pull OOTP data we need from the database.
  • On line 8 we load a list of years from the League model
  • Line 10 is an important step as we see if the user has submitted the form that will be in our view class or not. If they have,
    • We handle checking for and capturing the form input on lines 12 and 13
    • Next we check if we have a valid team_id value. If it’s false we bypass the next section to avoid errors. If true:
      • Lines 20-24 load the Players model from the OOTP Web Toolkit and construct a $records array that contains the output of two calls to the Players model get_current_stats() function. For the list of batters and their stats, we pass “2” as the first argument which is the position. This function considers 1 to be pitchers and anything else to be a hitter (the same as OOTPs player stats tables do using role to define pitching roles).
      • We then use the Template::set() method to create a variable called records in our view.
      • On the next line we set the year value if it was received
      • Finally on line 26 we call to the teams model to get details for the selected team id and set it to the view template for display
  • Back out of the Team_id if statement, we load two standard CodeIgniter helpers, form and url, and an OOTP Web Toolkit helper, general. We’ll see how these are used when we work on the view HTML code next.
  • Next we set an array to the view template called teams that contains a key/value pair of team id’s and names which we will use to fill our team drop down. You’ll notice we reference the “statslist.limit_to_primary” setting here to decide if we should pass a league_id to this function (which will return teams for only that league) or not.
  • We then pass down the $years array to the view to populate the year drop down and the settings array as well.
  • The Template::set_view() call is optional and not actually necessary. Bonfire will automatically try to search out a view that matches the name of your function. If it’s not found it will throw an error. I included this call just to show you could load another php file if needed before rendering the view.
  • The Template:render() call loads the view and sends the HTML output to the user.

Phew. That’s the controller. Save it and close it up.


Browse to and find “statslist/views/index.php”. Replace the Module Builder generated code with the following file:

index.php ZIP file

I posted the file as an attachment because it’s pretty sizeable. So replace your copy of “statslist/views/index.php” with this file and open it.

Let’s walk through it.

  • The entire contents of the page are wrapped in Twitter Bootstrap container and row tags.
  • In the top of the file, we define the page title and an intro blurb, both of which are pulled from the language library and styled according to Twitter bootstrap style conventions.
  • The next div block conditionally draws the team details. It is only drawn if a valid team_id is received from the controller so we use an isset() check to assure we don’t get an error. We use the FOSP asset_url setting to define the public URL to the assets HTML folder, then draw the 50 pixel team logo and team name using the PHP string replace method str_replace().
  • The next div block defines the Year and Team drop down boxes. They’re fairly straightforward and use the values passed down from the Leagues and Teams models respectively usingTemplate::set().
  • Now it’s onto the star of the show, the stats table. As with the team details, we check the validity of the $records variable (passed from the controller) before attempting to loop through it. We run isset(), is_array() and count() to verify this.
    if (isset($records) && is_array($records) && count($records)) :
  • Next we kick off the table display code. For efficiency sake, I created a two element $record array and a second array, $types, to loop through them. This allows you to reuse the same display logic code and customize the appropriate parts per each type you’re looping through, which in our case are some of the table headers. Using this approach, one could also add in stats for fielding to the list with hopefully minimal effort.
    $types = array('Batting','Pitching');
    	foreach ($types as $type) :
    		if (isset($records[$type]) && is_array($records[$type]) && count($records[$type])) :
  • Next we define the table using Twitter Bootstrap table classes. Then we define the table header. Some of the fields in $records will be the same and we embed an if statement to draw the appropriate stats headers depending on which stat type is being displayed.
    if ($type == 'Batting') :
  • After we define the <tbody>, it’s time to loop through the records themselves via a foreach loop.
    foreach($player as $field => $value) :
    SIDE NOTE: PHP Control Structures.
    In case you might not have noticed, in the view PHP pages I am using an alternate PHP control syntax which replaces the curly braces with colons and end statements. We do this to make the code in the view, which is intermixed with HTML and harder to navigate with curly braces, more manageable.
  • For each $records item, we first filter out an ID or role fields. We then utilize some of the functions found in the Open Sports Toolkit’s helpers/general_helper.php file, get_pos() to format position names and get_hand() to translate hand indexes to readable strings. We also use PHP’s sprint() to correctly format our floating point values like AVG and ERA.
  • The rest of our loop draws the value and closes up all our foreach and if statements.

If you save and upload these two files to your server and browse to the www.yousitename.com/statslist/ URL (and you have OOTP game data loaded on your server), you should be able to select a team and year and see stats similar to my own demo, North American Baseball League.


You’ve just stepped through building your first OOTP module for the FOSP.

Want to see the complete source for this demonstration? You can find it on Github at jfox015 -> OOTP StatsList. You can also view the working demo live at North American Baseball League. You can view the admin settings page by logging is as demo/demo.

Thanks for following along. I hope this was an informative demonstration of how to create tools using the Bonfire library for usage on the Fox Open Sports Platform.

Now go and get coding!

Download the FOSP Today!
Download the latest stable release version from the official FOSP web page. All the documentation you need is available in the installation and setup guide.

Contribute to the development and help the FOSP grow
The FOSP is a 100% free and open source project. The source code is publicly available on GitHub.com. If you want to contribute to the development, simply head over to my official Github page, fork the related projects, hack the code and send pull request with your updates. It’s that simple.

If you’ve built an FOSP module let me know and I’ll add it to the "Built on the FOSP" list.

Want to help test?
Testing assures everything works as expected and that everyone gets the best fantasy experience possible. Simply download and test the site and log issues on the official Github issues pages. Each portion of the site has its own page and issues list so be sure to log the issue in the appropriate module portion of the site.

While the FOSP is free to download and use, we do very much appreciate any donations made towards its development.


Jeff Fox is an over twenty-year web developer and digital user experience technology leader. Jeff cut his teeth in the Web's early days and is mainly self-taught in his professional skills. Having worked for a broad number of companies has helped build skills in development, organization and public speaking. In addition to being a passionate developer and technical speaker, Jeff is a dedicated tech and sci-fi geek gladly indulging in Doctor Who and Star Wars marathons. He is also a talented musician, writer and proud father of three little Foxies. And don't get him started about his San Francisco Giants.

Leave a Reply

Your email address will not be published.


This site uses Akismet to reduce spam. Learn how your comment data is processed.