検索機能の作成
ツイートモデルの変更
tweets.phpを以下のように修正します。
htdocs/Twitter/Models/tweets.php
<?php
// 設定ファイルの読み込み
include_once '../config.php';
// ツイート登録関数
function createTweet(array $data)
{
// データベースに接続
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// 成功/失敗確認
if ($mysqli->connect_errno) {
echo 'MySQLの接続に失敗しました。<br>';
exit;
}
// ツイート登録のSQLを作成
$query = 'INSERT INTO tweets (user_id, body, image_name) VALUES (?, ?, ?)';
// セキュリティ上、以下のように書く
$statement = $mysqli->prepare($query);
$statement->bind_param('iss', $data['user_id'], $data['body'], $data['image_name']);
// SQLを実行
$response = $statement->execute();
// 成功/失敗確認
if ($response == false) {
echo 'エラーが発生しました。<br>';
}
// データベースへの接続解除
$statement->close();
$mysqli->close();
// result変数には、true(成功)or false(失敗)が入っている
return $response;
}
// ★変更箇所1(ここから)
function getTweets($user, $keyword = null)
// ★変更箇所1(ここまで)
{
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// 成功/失敗確認
if ($mysqli->connect_errno) {
echo 'MySQLの接続に失敗しました。<br>';
exit;
}
// ログインしているユーザーのユーザーIDを取得
$user_id = $user['id'];
// ツイート一覧を取得するSQLを作成
$query = <<<SQL
SELECT
tweets.id AS tweet_id,
tweets.status AS tweet_status,
tweets.body AS tweet_body,
tweets.image_name AS tweet_image_name,
tweets.created_at AS tweet_created_at,
users.id AS user_id,
users.name AS user_name,
users.nickname AS user_nickname,
users.image_name AS user_image_name,
likes.id AS like_id,
(SELECT COUNT(*) FROM likes WHERE status = 'active' AND tweet_id = tweets.id) AS like_count
FROM
tweets
INNER JOIN users
ON users.id = tweets.user_id AND users.status = 'active'
LEFT JOIN
likes
ON likes.tweet_id = tweets.id AND likes.status = 'active' AND likes.user_id = '$user_id'
WHERE
tweets.status = 'active'
SQL;
// ★変更箇所2(ここから)
// 検索キーワードが指定された場合
if (isset($keyword)) {
// ツイートした人のニックネームとユーザー名と本文から部分一致で検索
$query .= ' AND CONCAT(users.nickname, users.name, tweets.body) LIKE "%' . $keyword . '%"';
// 新しい順に並び替え
$query .= ' ORDER BY tweets.created_at DESC';
// 表示件数は50件とする
$query .= ' LIMIT 50';
}
// ★変更箇所2(ここまで)
// SQLを実行
$result = $mysqli->query($query);
// 成功/失敗確認
if ($result == false) {
echo 'エラーが発生しました。<br>';
$mysqli->close(); // データベースへの接続解除
return false;
}
// ツイート一覧を取得
$tweets = $result->fetch_all(MYSQLI_ASSOC);
$mysqli->close();
return $tweets;
}
?>
変更箇所1について解説します。
引数$keywordを追加しています。「$keyword = null」のように書くことで、関数の呼び出し元がこの引数を指定しなかった場合、すなわちgetTweets($user)のように$keywordを指定せずに呼び出した場合、関数内で$keywordの中にはnullが入っていることになります。
変更箇所2について解説します。
$keywordが指定された場合、SQL文字列をさらに結合しています。元々のSQLの「WHERE tweets.status = ‘active’」の後に結合されることになります。
「CONCAT(users.nickname, users.name, tweets.body)」の部分に着目して下さい。COCAT関数はデータベースの関数で、引数で指定した値を結合してくれます。例えば、users.nicknameが「ichiro」、users.nameが「suzuki」、tweets.bodyが「こんにちは」だった場合、それらを結合すると「ichirosuzukiこんにちは」になります。これがCONCAT関数を実行した結果の値です。その値に対し、LIKEを使って指定された$keywordと部分一致があるかを判定しています。例えば、$keywordの値が「suzuki」だった場合、部分一致があることになりますね。
検索コントローラーの作成
Controllersフォルダ内に「search.php」ファイルを作成します。
search.phpに以下の内容を書きます。
htdocs/Twitter/Controllers/search.php
<?php
include_once '../util.php';
// ツイートモデルを読み込み
include_once '../Models/tweets.php';
// ログインチェック
$view_user = getSession();
if ($view_user == false) {
// ログインしていない
header('Location: ../Controllers/sign-in.php');
exit;
}
$keyword = null;
// 検索キーワードを取得
if (isset($_GET['keyword'])) {
$keyword = $_GET['keyword'];
}
// ツイート一覧取得
$view_tweets = getTweets($view_user, $keyword);
// 画面表示
include_once '../Views/search.php';
?>
キーワードが指定された場合、$_GET[‘keyword’]でキーワードを取り出し、getTweets関数に渡しています。
プロフィール編集機能の作成
ユーザーモデルの変更
users.phpを以下のように修正します。
htdocs/Twitter/Models/users.php
<?php
// 設定ファイルの読み込み
include_once '../config.php';
// ユーザー登録関数
function createUser($data)
{
// データベースに接続
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// 成功/失敗確認
if ($mysqli->connect_errno) {
echo 'MySQLの接続に失敗しました。<br>';
exit;
}
// ユーザー登録のSQLを作成
$query = 'INSERT INTO users (email, name, nickname, password) VALUES (?, ?, ?, ?)';
// セキュリティ上、以下のように書く
$statement = $mysqli->prepare($query);
$statement->bind_param('ssss', $data['email'], $data['name'], $data['nickname'], $data['password']);
// SQLを実行
$response = $statement->execute();
// 成功/失敗確認
if ($response == false) {
echo 'エラーが発生しました。<br>';
}
// データベースへの接続解除
$statement->close();
$mysqli->close();
// result変数には、true(成功)or false(失敗)が入っている
return $response;
}
// ログイン関数
function login($email, $password)
{
// データベースに接続
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// 成功/失敗確認
if ($mysqli->connect_errno) {
echo 'MySQLの接続に失敗しました。<br>';
exit;
}
// ユーザー情報取得のSQLを作成
$query = 'SELECT * FROM users WHERE email = "'.$email.'"';
// SQLを実行
$result = $mysqli->query($query);
// 成功/失敗確認
if ($result == false) {
echo 'エラーが発生しました。<br>';
$mysqli->close(); // データベースへの接続解除
return false;
}
// ユーザー情報を取得
$user = $result->fetch_array(MYSQLI_ASSOC);
if ($user == false) {
echo 'ユーザーが存在しません。<br>';
$mysqli->close(); // データベースへの接続解除
return false;
}
// パスワードチェック
if ($password != $user['password']) {
echo 'パスワードが一致しません。<br>';
$mysqli->close(); // データベースへの接続解除
return false;
}
// データベースへの接続解除
$mysqli->close();
// ユーザー情報を返す
return $user;
}
// ★変更箇所1(ここから)
// ユーザー情報取得
function getUser($user_id)
{
// データベースに接続
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// 成功/失敗確認
if ($mysqli->connect_errno) {
echo 'MySQLの接続に失敗しました。<br>';
exit;
}
// ユーザー情報取得のSQLを作成
$query = 'SELECT * FROM users WHERE id = "'.$user_id.'"';
// SQLを実行
$result = $mysqli->query($query);
// 成功/失敗確認
if ($result == false) {
echo 'エラーが発生しました。<br>';
$mysqli->close(); // データベースへの接続解除
return false;
}
// ユーザー情報を取得
$user = $result->fetch_array(MYSQLI_ASSOC);
if ($user == false) {
echo 'ユーザーが存在しません。<br>';
$mysqli->close(); // データベースへの接続解除
return false;
}
// データベースへの接続解除
$mysqli->close();
// ユーザー情報を返す
return $user;
}
// ★変更箇所1(ここまで)
// ★変更箇所2(ここから)
// ユーザー情報更新
function updateUser($data)
{
// データベースに接続
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
// 成功/失敗確認
if ($mysqli->connect_errno) {
echo 'MySQLの接続に失敗しました。<br>';
exit;
}
// ユーザー情報更新のSQLを作成
$dataset = '';
$dataset = $dataset.'name="'.$data['name'].'"';
$dataset = $dataset.',';
$dataset = $dataset.'nickname="'.$data['nickname'].'"';
$dataset = $dataset.',';
$dataset = $dataset.'email="'.$data['email'].'"';
if (isset($data['image_name'])) {
$dataset = $dataset.',';
$dataset = $dataset.'image_name="'.$data['image_name'].'"';
}
if (isset($data['password'])) {
$dataset = $dataset.',';
$dataset = $dataset.'password="'.$data['password'].'"';
}
$query = 'UPDATE users SET '. $dataset;
$query = $query.' WHERE id = "'.$data['id'].'"';
// SQLを実行
$result = $mysqli->query($query);
// 成功/失敗確認
if ($result == false) {
echo 'エラーが発生しました。<br>';
$mysqli->close(); // データベースへの接続解除
return false;
}
// データベースへの接続解除
$mysqli->close();
return $result;
}
// ★変更箇所2(ここまで)
?>
ユーザー情報を取得する「getUser関数」と、ユーザー情報を更新する「updateUser関数」を追加しました。
プロフィールコントローラーの作成
Controllersフォルダ内に「profile.php」ファイルを作成します。
profile.phpに以下の内容を書きます。
htdocs/Twitter/Controllers/profile.php
<?php
include_once '../util.php';
// ユーザーモデルを読み込み
include_once '../Models/users.php';
// ログインチェック
$view_user = getSession();
if ($view_user == false) {
// ログインしていない
header('Location: ../Controllers/sign-in.php');
exit;
}
// ユーザー情報の更新
if (isset($_POST['nickname']) && isset($_POST['name']) && isset($_POST['email'])) {
$data = [
'id' => $view_user['id'],
'name' => $_POST['name'],
'nickname' => $_POST['nickname'],
'email' => $_POST['email'],
];
// パスワードが入力されている場合
if (isset($_POST['password'])) {
$data['password'] = $_POST['password'];
}
// ファイルがアップロードされている場合
if (isset($_FILES['image']) && is_uploaded_file($_FILES['image']['tmp_name'])) {
$data['image_name'] = saveFile($view_user, $_FILES['image'], 'user');
}
// ユーザー情報を更新
$result = updateUser($data);
if ($result) {
// 成功したらセッション情報も更新
$view_user = getUser($view_user['id']);
saveSession($view_user);
// 成功したらプロフィール画面に遷移(リロード)
header('Location: ../Controllers/profile.php');
exit;
}
}
// 画面表示
include_once '../Views/profile.php';
?>
ユーザー情報の更新をしたら、再度ユーザー情報を取得してセッション情報も更新しています。
プロフィールビューの変更
profile.phpを以下のように修正します。
htdocs/Twitter/Views/profile.php
<!DOCTYPE html>
<html>
<lang="ja">
<head>
<?php include_once('../Views/common/header.php'); ?>
<title>プロフィール</title>
</head>
<!-- ★変更箇所(ここから)-->
<body class="home profile">
<div class="container">
<?php include_once('../Views/common/side.php'); ?>
<div class="main">
<div class="main-header">
<h1><?php echo $view_user['nickname']; ?></h1>
</div>
<!-- プロフィールエリア -->
<div class="profile-area">
<div class="top">
<div class="user"><img src="<?php echo $view_user['image_name']; ?>" alt=""></div>
<?php if (isset($_GET['user_id'])) : ?>
<!-- 他のユーザーのWebページ -->
<?php if (isset($_GET['case'])) : ?>
<button class="btn btn-sm">フォローをやめる</button>
<?php else : ?>
<button class="btn btn-sm btn-reverse">フォローする</button>
<?php endif; ?>
<?php else : ?>
<!-- 自分のWebページ -->
<button class="btn btn-reverse btn-sm" data-bs-toggle="modal" data-bs-target="#js-modal">プロフィール編集</button>
<?php endif; ?>
</div>
<div class="name"><?php echo $view_user['nickname']; ?></div>
<div class="text-muted">@<?php echo $view_user['name']; ?></div>
<div class="follow-follower">
<div class="follow-count">1</div>
<div class="follow-text">フォロー中</div>
<div class="follow-count">1</div>
<div class="follow-text">フォロワー</div>
</div>
</div>
<!-- 仕切りエリア -->
<div class="ditch"></div>
<!-- ツイート一覧エリア -->
<?php if (empty($view_tweets)): ?>
<p class="p-3">ツイートがありません</p>
<?php else: ?>
<div class="tweet-list">
<?php foreach ($view_tweets as $view_tweet) : ?>
<?php include('../Views/common/tweet.php'); ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
<!-- モーダル -->
<div class="modal" id="js-modal">
<div class="modal-dialog">
<div class="modal-content">
<form action="profile.php" method="post" enctype="multipart/form-data">
<div class="modal-header">
<h5 class="modal-title">プロフィール編集</h5>
<button class="btn-close" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="user">
<img src="<?php echo $view_user['image_name']; ?>" alt="">
</div>
<div class="mb-3">
<label for="" class="mb-1">プロフィール写真</label>
<input type="file" class="form-control form-control-sm" name="image">
</div>
<input type="text" class="form-control mb-4" name="nickname" value="<?php echo $view_user['nickname']; ?>" placeholder="ニックネーム" maxlength="50" required>
<input type="text" class="form-control mb-4" name="name" value="<?php echo $view_user['name']; ?>" placeholder="ユーザー名" maxlength="50" required>
<input type="email" class="form-control mb-4" name="email" value="<?php echo $view_user['email']; ?>" placeholder="メールアドレス" maxlength="254" required>
<input type="password" class="form-control mb-4" name="password" value="<?php echo $view_user['password']; ?>" placeholder="" minlength="4" maxlength="128">
</div>
<div class="modal-footer">
<button class="btn btn-reverse" data-bs-dismiss="modal">キャンセル</button>
<button class="btn" type="submit">保存する</button>
</div>
</form>
</div>
</div>
</div>
</body>
<!-- ★変更箇所(ここまで)-->
</html>
各プロフィール情報を、PHPの$view_userの値を出力するようにしています。
ここまで出来たら、以下のようにプロフィール編集ができるようになっていますので確認して下さい。
ホームビューの変更
home.phpを以下のように修正します。
htdocs/Twitter/Views/home.php
<!DOCTYPE html>
<html>
<lang="ja">
<head>
<?php include_once('../Views/common/header.php'); ?>
<title>Twitter</title>
</head>
<body class="home">
<div class="container">
<?php include_once('../Views/common/side.php'); ?>
<div class="main">
<div class="main-header">
<h1>ホーム</h1>
</div>
<div class="tweet-post">
<div class="my-icon">
<!-- ★変更箇所(ここから)-->
<img src="<?php echo $view_user['image_name']; ?>" alt="">
<!-- ★変更箇所(ここまで)-->
</div>
<div class="input-area">
<form action="post.php" method="post" enctype="multipart/form-data">
<textarea name="body" placeholder="Hello" maxlength="140"></textarea>
<div class="bottom-area">
<div class="mb-0">
<input type="file" name="image" class="form-control form-control-sm">
</div>
<button class="btn" type="submit">つぶやく</button>
</div>
</form>
</div>
</div>
<div class="ditch"></div>
<?php if (empty($view_tweets)): ?>
<p class="p-3">ツイートがありません</p>
<?php else: ?>
<div class="tweet-list">
<?php foreach ($view_tweets as $view_tweet) : ?>
<?php include('../Views/common/tweet.php'); ?>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
</body>
</html>
サイド領域の変更
サイド領域を以下のように修正します。
htdocs/Twitter/Views/common/side.php
<div class="side">
<div class="side-inner">
<ul class="nav flex-column">
<li class="nav-item"><a href="home.php" class="nav-link"><img src="../Views/img/1.svg" alt="" class="icon"></a></li>
<li class="nav-item"><a href="home.php" class="nav-link"><img src="../Views/img/2.svg" alt=""></a></li>
<li class="nav-item"><a href="search.php" class="nav-link"><img src="../Views/img/3.svg" alt=""></a></li>
<li class="nav-item"><a href="notification.php" class="nav-link"><img src="../Views/img/4.svg" alt=""></a></li>
<li class="nav-item"><a href="profile.php" class="nav-link"><img src="../Views/img/5.svg" alt=""></a></li>
<li class="nav-item"><a href="post.php" class="nav-link"><img src="../Views/img/6.svg" alt="" class="icon"></a></li>
<!-- ★変更箇所(ここから)-->
<li class="nav-item"><img src="<?php echo $view_user['image_name']; ?>" alt="" class="my-icon"></li>
<!-- ★変更箇所(ここまで)-->
<li><a href="sign-out.php" class="nav-link">logout</a></li>
</ul>
</div>
</div>
これで、プロフィール編集結果が、ホーム画面およびサイド領域に反映されるようになりました。
通知機能の作成
通知機能とは、他者からいいねやフォローをされたことを表示する機能です。
ここでは通知コントローラーのひな形を追加するだけに留めます。
余力がある方は、これまでの学習内容を参考に、自分なりに機能を追加してみて下さい。
通知コントローラーの作成
Controllersフォルダ内に「notification.php」ファイルを作成します。
notification.phpに以下の内容を書きます。
htdocs/Twitter/Controllers/notification.php
<?php
// 画面表示
include_once '../Views/notification.php';
?>
ここまで出来たら、変更内容をコミットし、GitHubにプッシュして下さい。
本節の説明は以上になります。
トップページ <<前のカリキュラムへ戻る 次のカリキュラムへ進む [Windows] [Mac] >>