Make your own blog
Adding more features
It is normal practice to link the main heading of a website to the home page, as this makes for a consistent navigation experience. So, let's do that now:
 
		 
	- templates/title.php templates/title.php
 
				1
					 
					 
					2
					<h1>Blog title</h1>
					<p>This paragraph summarises what the blog is about.</p>
					1
					2
					3
					4
					<a href="index.php">
						<h1>Blog title</h1>
					</a>
					<p>This paragraph summarises what the blog is about.</p>
					Next, let us add in some logic that interprets two carriage-returns in a post as a paragraph break. Here we go:
 
		 
	- view-post.php view-post.php
 
				36
					37
					38
					 
					 
					 
					 
					39
					40
					41
					60
					61
					62
					63
					 
					64
					65
					66
					// Let's get a row
					$row = $stmt->fetch(PDO::FETCH_ASSOC);
					?>
					<!DOCTYPE html>
					<html>
								<?php echo $row['created_at'] ?>
							</div>
							<p>
								<?php echo htmlEscape($row['body']) ?>
							</p>
						</body>
					</html>
					36
					37
					38
					39
					40
					41
					42
					43
					44
					45
					60
					61
					62
					63
					64
					65
					66
					67
					// Let's get a row
					$row = $stmt->fetch(PDO::FETCH_ASSOC);
					// Swap carriage returns for paragraph breaks
					$bodyText = htmlEscape($row['body']);
					$paraText = str_replace("\n", "</p><p>", $bodyText);
					?>
					<!DOCTYPE html>
					<html>
								<?php echo $row['created_at'] ?>
							</div>
							<p>
								<?php // This is already escaped, so doesn't need further escaping ?>
								<?php echo $paraText ?>
							</p>
						</body>
					</html>
					Now, the default date style used around the application isn't very readable, so let's improve that now:
 
		 
	- index.php index.php
- lib/common.php lib/common.php
- view-post.php view-post.php
 
				31
					32
					33
					34
					35
					36
					37
									<?php echo htmlEscape($row['title']) ?>
								</h2>
								<div>
									<?php echo $row['created_at'] ?>
								</div>
								<p>
									<?php echo htmlEscape($row['body']) ?>
					31
					32
					33
					34
					35
					36
					37
									<?php echo htmlEscape($row['title']) ?>
								</h2>
								<div>
									<?php echo convertSqlDate($row['created_at']) ?>
								</div>
								<p>
									<?php echo htmlEscape($row['body']) ?>
					50
					51
					52
					{
						return htmlspecialchars($html, ENT_HTML5, 'UTF-8');
					}
					50
					51
					52
					53
					54
					55
					56
					57
					58
					59
					60
					{
						return htmlspecialchars($html, ENT_HTML5, 'UTF-8');
					}
					function convertSqlDate($sqlDate)
					{
						/* @var $date DateTime */
						$date = DateTime::createFromFormat('Y-m-d', $sqlDate);
						return $date->format('d M Y');
					}
					57
					58
					59
					60
					61
					62
					63
								<?php echo htmlEscape($row['title']) ?>
							</h2>
							<div>
								<?php echo $row['created_at'] ?>
							</div>
							<p>
								<?php // This is already escaped, so doesn't need further escaping ?>
					57
					58
					59
					60
					61
					62
					63
								<?php echo htmlEscape($row['title']) ?>
							</h2>
							<div>
								<?php echo convertSqlDate($row['created_at']) ?>
							</div>
							<p>
								<?php // This is already escaped, so doesn't need further escaping ?>
					Now we've done a bit of tidying, let's tackle a bigger item of functionality. We need to allow users to comment on articles, so let's make the necessary database changes to prepare for that:
 
		 
	- data/init.sql data/init.sql
- install.php install.php
 
				54
					55
					56
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					57
							1,
							date('now', '-13 days')
						)
					;
					54
					55
					56
					57
					58
					59
					60
					61
					62
					63
					64
					65
					66
					67
					68
					69
					70
					71
					72
					73
					74
					75
					76
					77
					78
					79
					80
					81
					82
					83
					84
					85
					86
					87
					88
					89
					90
					91
					92
					93
					94
					95
					96
							1,
							date('now', '-13 days')
						)
					;
					DROP TABLE IF EXISTS comment;
					CREATE TABLE comment (
						id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
						post_id INTEGER NOT NULL,
						created_at VARCHAR NOT NULL,
						name VARCHAR NOT NULL,
						website VARCHAR,
						text VARCHAR NOT NULL
					);
					INSERT INTO
						comment
						(
							post_id, created_at, name, website, text
						)
						VALUES(
							1,
							date('now', '-10 days'),
							'Jimmy',
							'http://example.com/',
							"This is Jimmy's contribution"
						)
					;
					INSERT INTO
						comment
						(
							post_id, created_at, name, website, text
						)
						VALUES(
							1,
							date('now', '-8 days'),
							'Jonny',
							'http://anotherexample.com/',
							"This is a comment from Jonny"
						)
					;
					49
					50
					51
					52
					53
					 
					54
					55
					56
					57
					58
					59
					 
					 
					 
					 
					 
					 
					60
					61
					62
					93
					94
					95
					96
					97
					98
					 
					 
					 
					 
					 
					 
					 
					99
					100
					101
					}
					// See how many rows we created, if any
					$count = null;
					if (!$error)
					{
						$sql = "SELECT COUNT(*) AS c FROM post";
						$stmt = $pdo->query($sql);
						if ($stmt)
						{
							$count = $stmt->fetchColumn();
						}
					}
							<?php else: ?>
								<div class="success box">
									The database and demo data was created OK.
									<?php if ($count): ?>
										<?php echo $count ?> new rows were created.
									<?php endif ?>
								</div>
							<?php endif ?>
						</body>
					49
					50
					51
					52
					53
					54
					55
					56
					 
					 
					57
					58
					59
					60
					61
					62
					63
					64
					65
					66
					67
					93
					94
					95
					96
					97
					98
					99
					100
					101
					102
					103
					104
					105
					106
					107
					108
					}
					// See how many rows we created, if any
					$count = array();
					foreach(array('post', 'comment') as $tableName)
					{
						if (!$error)
						{
							$sql = "SELECT COUNT(*) AS c FROM " . $tableName;
							$stmt = $pdo->query($sql);
							if ($stmt)
							{
								// We store each count in an associative array
								$count[$tableName] = $stmt->fetchColumn();
							}
						}
					}
							<?php else: ?>
								<div class="success box">
									The database and demo data was created OK.
									<?php foreach (array('post', 'comment') as $tableName): ?>
										<?php if (isset($count[$tableName])): ?>
											<?php // Prints the count ?>
											<?php echo $count[$tableName] ?> new
											<?php // Prints the name of the thing ?>
											<?php echo $tableName ?>s
											were created.
										<?php endif ?>
									<?php endforeach ?>
								</div>
							<?php endif ?>
						</body>
					
	Since this involves database changes, we'll need to delete our database file, and re-run
	the installer. So, delete the file in data/data.sqlite and then
	reinstall by visiting http://localhost/install.php again.
You might ask why we are putting so much effort into an installer when we're nowhere near having a piece of finished software. The answer is that this installer is for us, the developers, and not for end users. Thus, it is something we want to set up reasonably early in our development lifecycle; whenever a database change is made, we want to be able to recreate our useful test data quickly and easily.
	Now we're ready to start adding some comment-related changes. To start with, let's add
	a count of comments on the front page. This uses the SQL command COUNT() to count
	the number of rows that would be returned by a query:
 
		 
	- index.php index.php
- lib/common.php lib/common.php
 
				32
					33
					34
					 
					 
					35
					36
					37
								</h2>
								<div>
									<?php echo convertSqlDate($row['created_at']) ?>
								</div>
								<p>
									<?php echo htmlEscape($row['body']) ?>
					32
					33
					34
					35
					36
					37
					38
					39
								</h2>
								<div>
									<?php echo convertSqlDate($row['created_at']) ?>
									(<?php echo countCommentsForPost($row['id']) ?> comments)
								</div>
								<p>
									<?php echo htmlEscape($row['body']) ?>
					58
					59
					60
						return $date->format('d M Y');
					}
					58
					59
					60
					61
					62
					63
					64
					65
					66
					67
					68
					69
					70
					71
					72
					73
					74
					75
					76
					77
					78
					79
					80
					81
					82
					83
					84
					85
						return $date->format('d M Y');
					}
					/**
					 * Returns the number of comments for the specified post
					 *
					 * @param integer $postId
					 * @return integer
					 */
					function countCommentsForPost($postId)
					{
						$pdo = getPDO();
						$sql = "
							SELECT
								COUNT(*) c
							FROM
								comment
							WHERE
								post_id = :post_id
						";
						$stmt = $pdo->prepare($sql);
						$stmt->execute(
							array('post_id' => $postId, )
						);
						return (int) $stmt->fetchColumn();
					}
					Also, we'll add a comment listing to individual post pages:
 
		 
	- lib/common.php lib/common.php
- view-post.php view-post.php
 
				83
					84
					85
						return (int) $stmt->fetchColumn();
					}
					83
					84
					85
					86
					87
					88
					89
					90
					91
					92
					93
					94
					95
					96
					97
					98
					99
					100
					101
					102
					103
					104
					105
					106
					107
					108
					109
						return (int) $stmt->fetchColumn();
					}
					/**
					 * Returns all the comments for the specified post
					 *
					 * @param integer $postId
					 */
					function getCommentsForPost($postId)
					{
						$pdo = getPDO();
						$sql = "
							SELECT
								id, name, text, created_at, website
							FROM
								comment
							WHERE
								post_id = :post_id
						";
						$stmt = $pdo->prepare($sql);
						$stmt->execute(
							array('post_id' => $postId, )
						);
						return $stmt->fetchAll(PDO::FETCH_ASSOC);
					}
					63
					64
					65
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					 
					66
					67
								<?php // This is already escaped, so doesn't need further escaping ?>
								<?php echo $paraText ?>
							</p>
						</body>
					</html>
					63
					64
					65
					66
					67
					68
					69
					70
					71
					72
					73
					74
					75
					76
					77
					78
					79
					80
					81
					82
					83
					84
					85
								<?php // This is already escaped, so doesn't need further escaping ?>
								<?php echo $paraText ?>
							</p>
							<h3><?php echo countCommentsForPost($postId) ?> comments</h3>
							<?php foreach (getCommentsForPost($postId) as $comment): ?>
								<?php // For now, we'll use a horizontal rule-off to split it up a bit ?>
								<hr />
								<div class="comment">
									<div class="comment-meta">
										Comment from
										<?php echo htmlEscape($comment['name']) ?>
										on
										<?php echo convertSqlDate($comment['created_at']) ?>
									</div>
									<div class="comment-body">
										<?php echo htmlEscape($comment['text']) ?>
									</div>
								</div>
							<?php endforeach ?>
						</body>
					</html>
					So, give that a whirl. You will want to check the new count on the homepage, and the comments feature on individual posts. How's that looking?
 Download
						Download