Codeigniter Doctrine Today we will continue building our Message Board project. First we will start building the Home Page, which will be a Forum List. Then we will learn about Doctrine Data Fixtures. This will help us create some test data to play with.

"CodeIgniter and Doctrine from Scratch" Series:

download_code

First, Some Styling

Before we get started, let’s add some style so that pages look somewhat decent. Just copy-paste, and don’t read it. CSS is not our focus today.

  • Edit: css/style.css
body {
	font-family: "Trebuchet MS",Arial;
	font-size: 14px;
	background-color: #212426;
	color: #B9AA81;
}

a {
	color: #FFF;
}

a:hover {
	color: #B9AA81;
}

input, textarea, select {
	font-family:inherit;
	font-size:inherit;
	font-weight:inherit;
}

/* FORUMS -----------------------------------------*/

div.forums {
	width: 720px;
	margin: auto;
}

.forums h2 {
	font-size: 16px;
	color: #000;
	padding: 5px 10px 5px 10px;
	margin: 0px;
	background-color: #BBB;
	-moz-border-radius-topleft: 6px;
	-moz-border-radius-topright: 6px;
	-webkit-border-top-left-radius: 6px;
	-webkit-border-top-right-radius: 6px;
}

.forums h3 {
	font-size: 15px;
	margin: 0px;
}

.category {
	margin-bottom: 40px;
}

.forum {
	border-bottom: 1px solid #666;
	padding: 10px;
}

.forum .description {
	font-size: 14px;
}

/* SIGNUP FORM ------------------------------------*/
#signup_form {
	margin-left: auto;
	margin-right: auto;
	width: 360px;
	font-size: 16px;
}

#signup_form .heading {
	text-align: center;
	font-size: 22px;
	font-weight: bold;
	color: #B9AA81;
}

#signup_form form {
	background-color: #B9AA81;
	padding: 10px;
	border-radius: 8px;
	-moz-border-radius: 8px;
	-webkit-border-radius: 8px;
}

#signup_form form label {
	font-weight: bold;
	color: #11151E;
}

#signup_form form input[type=text],input[type=password] {
	width: 316px;
	font-weight: bold;
	padding: 8px;
	border: 1px solid #FFF;
	border-radius: 4px;
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
}

#signup_form form input[type=submit] {
	display: block;
	margin: auto;
	width: 200px;
	font-size: 18px;
	background-color: #FFF;
	border: 1px solid #BBB;

}

#signup_form form input[type=submit]:hover {
	border-color: #000;
}

#signup_form .error {
	font-size: 13px;
	color: #690C07;
	font-style: italic;
}

Ok, now we’re ready to get more coding done!

The Home Page

We are about to work on the Controller and the View for our Home Page (i.e. Forum List). We want this page to show all of the Forums broken down by Categories.

Home Controller

  • Edit: system/application/controllers/home.php
<?php
class Home extends Controller {

	public function index() {

		$vars['categories'] = Doctrine::getTable('Category')->findAll();

		$this->load->view('home', $vars);
	}	

}

As mentioned before, variables are passed to a View in an array, and the array indexes become variable names. In other words, $vars['categories'] becomes $categories inside the View.

Doctrine::getTable(‘Category’)->findAll(); gives us all of the Category records, in the form of a Doctrine_Collection object.

Home View

(I’m going build this page in a few steps)

  • Edit: system/application/views/home.php

First we make a blank page, with a container div and a heading:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>Home</title>
	<link rel="stylesheet" href="<?php echo base_url(); ?>css/style.css"
		type="text/css" media="all">
</head>
<body>

<div class="forums">

	<h1>CI+Doctrine Message Board</h1>

</div>

</body>
</html>

Next, we loop thru the $categories object, and display titles for each Category:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>Home</title>
	<link rel="stylesheet" href="<?php echo base_url(); ?>css/style.css"
		type="text/css" media="all">
</head>
<body>

<div class="forums">

	<h1>CI+Doctrine Message Board</h1>

	<?php foreach($categories as $category): ?>

		<div class="category">

			<h2><?php echo $category->title; ?></h2>

		</div>

	<?php endforeach; ?>

</div>

</body>
</html>

Note: $categories is a Doctrine_Collection object here, but it can be treated like an array. So we can use foreach on it.

Now we are going to show each Forum, their descriptions, and number of Threads.

<!DOCTYPE html>
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>Home</title>
	<link rel="stylesheet" href="<?php echo base_url(); ?>css/style.css"
		type="text/css" media="all">
</head>
<body>

<div class="forums">

	<h1>CI+Doctrine Message Board</h1>

	<?php foreach($categories as $category): ?>

		<div class="category">

			<h2><?php echo $category->title; ?></h2>

			<?php foreach($category->Forums as $forum): ?>

				<div class="forum">

					<h3>
						<?php echo anchor('forums/'.$forum->id, $forum->title) ?>
						(<?php echo $forum->Threads->count(); ?> threads)
					</h3>

					<div class="description">
						<?php echo $forum->description; ?>
					</div>

				</div>

			<?php endforeach; ?>

		</div>

	<?php endforeach; ?>

</div>

</body>
</html>

As you can see, getting all Forums under a Category is as easy as calling $category->Forums. And again, we can treat it as an array and loop thru it.

Line 26: We are creating a link to the Forum. It will link to a Controller named Forums and pass the id in the url. And the link text is the Forum title.

Note: In CodeIgniter, Controllers and Models cannot have the same name. That’s why I linked to ‘forums’ instead of ‘forum’. Some people might prefer ‘view_forum’ or ‘show_forum’ etc…

Line 27: This is the first time we are using count(). That’s how we get the number of Threads that belong to that Forum object.

The Result

You will see this:

ci_doctrine_day7_1

Looks nice. But the links are broken since we haven’t created the Forums Controller (i.e. Forum Page) yet.

Now, we could go ahead and build the Forum Page, but it’s just not going to look very good since we have no Threads or Posts whatsoever. This is a great time to start talking about Data Fixtures.

Doctrine Data Fixtures

What are Data Fixtures?

Data fixtures are meant for loading small sets of test data through your models to populate your database with data to test against.” (from here).

This will do the job for filling the database with some data, so we can do proper testing as we develop our project.

In the last article, we created a Test Controller for inserting some data. That worked well for this tutorial, and we saw some code examples along the way. But on a real development environment, it’s better to just use Data Fixtures.

Creating Fixtures

First, we need to have a place to put our Fixtures. You can put this folder anywhere, but I would like to create it directly under the applications folder.

  • Create Folder: system/application/fixtures
  • Create: system/application/fixtures/data.yml

That’s right, we are creating a YAML file. Don’t worry if you are not familiar with this file format.

We are going to start small with an example:

User:
  Admin:
    username: Administrator
    password: testing
    email: programming@gmail.com
  Test:
    username: TestUser
    password: mypass
    email: test@test.com

Even if you are not familiar with YAML, the structure is easy to understand.
This code just creates 2 User records.

Note: I used 2 spaces for indentation, but it can be any number of spaces. And Tabs do NOT work.

  • First line is the name of the Model we are loading data for.
  • Line 2 and 6: These are just names for these records. They can be anything. We can use them later in the fixture to reference these records.
  • The rest should be obvious. We are assigning data to each field for these records.

Now, we need to load this fixture into the database.

  • Edit: system/application/controllers/doctrine_tools.php
<?php
class Doctrine_Tools extends Controller {

// ....

	function load_fixtures() {
		echo 'This will delete all existing data!<br />
		<form action="" method="POST">
		<input type="submit" name="action" value="Load Fixtures"><br /><br />';

		if ($this->input->post('action')) {

			Doctrine_Manager::connection()->execute(
				'SET FOREIGN_KEY_CHECKS = 0');

			Doctrine::loadData(APPPATH.'/fixtures');
			echo "Done!";
		}
	}

}

We added a function named load_fixtures() to this Controller.

Doctrine:loadData() does the work. Every time it is called, it will purge existing data from the tables, and load the Data Fixtures from the given path. If you don’t want the table purge to happen, you need to pass a second argument as true.

(I also had to disable FOREIGN_KEY_CHECKS to avoid some foreign key related errors during the purge.)

ci_doctrine_day7_2

Now that everything seems to be working, let’s expand our fixture so we have more data to work with.

  • Edit: system/application/fixtures/data.yml
User:
  Admin:
    username: Administrator
    password: testing
    email: programming@gmail.com
  Test:
    username: TestUser
    password: mypass
    email: test@test.com
  Foo:
    username: Foobar
    password: mypass
    email: test2@test2.com

Forum:
  Forum_1:
    title: Introduce Yourself!
    description: >
      Use this forum to introduce yourself to the CodeIgniter community,
      or to announce your new CI powered site.
  Forum_2:
    title: The Lounge
    description: >
      CodeIgniter's social forum where you can discuss anything not related
      to development. No topics off limits... but be civil.
  Forum_3:
    title: CodeIgniter Discussion
    description: This forum is for general topics related to CodeIgniter.
  Forum_4:
    title: Code and Application Development
    description: >
      Use the forum to discuss anything related to
      programming and code development.
  Forum_5:
    title: Ignited Code
    description: >
      Use this forum to post plugins, libraries, or other code contributions,
      or to ask questions about any of them.

Category:
  Lounge:
    title: The CodeIgniter Lounge
    Forums: [Forum_1, Forum_2]
  Dev:
    title: CodeIgniter Development Forums
    Forums: [Forum_3, Forum_4, Forum_5]

Thread:
  Thread_1:
    title: Hi there!
    Forum: Forum_1
  Thread_2:
    title: Greetings to all
    Forum: Forum_1

Post:
  Post_1:
    Thread: Thread_1
    User: Test
    created_at: 2009-11-20 01:20:30
    content: >
      Hello everyone! My name is Test, and I go to school at
      Test Institute of Technology in the US.
      I just found CodeIgniter some time last week and have been
      reading through the documentation trying to get myself acquainted.

      Hopefully the forums will be a great help! I already have some questions.
      Thanks!
  Post_2:
    Thread: Thread_1
    User: Admin
    created_at: 2009-11-20 02:15:33
    content: Welcome Test! Nice to meet you.
  Post_3:
    Thread: Thread_2
    User: Foo
    created_at: 2009-11-19 12:14:50
    content: I am new here. Just wanted to say hi.

This is just a bunch of structured data, nothing complicated. For each Model, we create a few records. And we have a few new things to mention:

Line 18: Here you can see the syntax for adding a long string value in multiple lines.
Line 51: We are setting up the relationships between records. This line says Thread_1 belongs to Forum_1.
Line 43: Again, we are setting up relationships, but this time we are assigning multiple records, and you see the syntax for that.

ci_doctrine_day7_3

We just created 15 records!

See the Results

ci_doctrine_day7_4

We can see all the Categories and Forums we just created. Also there are 2 Threads now, as we can see from the count.

Stay Tuned

Our Message Board is starting to take shape. Meanwhile we learned about a new concept called Data Fixtures, which is very helpful during the development process.

In the next tutorials we will go deeper into the project and keep building more functional pages.

See you next time!

"CodeIgniter and Doctrine from Scratch" Series: