はじめに
前回の記事では、PHPを使った週間スケジュール管理システムの基本を構築しました。今回は、そのシステムをより使いやすく、より管理しやすいものへと改良していきます。
具体的には、データ構造の見直し、未入力状態の追加、古いデータの自動削除など、実用的な機能を追加しました。開発を進める中で浮かび上がった問題点と、その解決策を見ていきましょう。
最初に浮上した課題
システムを実際に使い始めると、いくつかの改善点が見えてきました。
- まず、公開ページと管理ページの行き来が不便でした。公開ページから管理画面へ、管理画面から公開ページへ、それぞれ直接移動できるリンクがなかったのです。管理者は毎回URLを直接入力する必要がありました。
- 次に、表示時刻の問題です。公開ページには「現在時刻」が表示されていましたが、これではスケジュールがいつ更新されたのかわかりません。訪問者が見たいのは、このスケジュールがいつ登録されたものかという情報です。
- そして、スタイルシートの問題もありました。CSSがHTMLに直接書かれていたため、デザインを変更したいときに不便でした。
ページ間リンクの追加
最初の改善は簡単でした。公開ページの下部に、目立たないリンクを追加します。小さな点「・」を薄いグレー色で配置しました。これなら一般の訪問者には気づかれにくく、管理者だけが知っているリンクとして機能します。
管理画面のログインページには、「スケジュールを表示」というリンクを追加しました。ログインする前でも公開ページを確認できるようになります。
CSSでは、リンクの色とサイズを調整しました。
.admin-link {
text-align: center;
margin-top: 30px;
font-size: 10px;
}
.admin-link a {
color: #ccc;
text-decoration: none;
}
Code language: CSS (css)
更新時刻の記録
次に取り組んだのは、更新時刻の表示です。公開ページに表示する時刻を、現在時刻からデータの更新時刻に変更しました。
config.phpのsaveData()関数を修正して、データを保存するときに更新時刻も記録します。
function saveData($data) {
$data['_updated_at'] = date('Y年n月j日 G時i分');
file_put_contents(DATA_FILE, json_encode($data, JSON_PRETTY_PRINT));
}
Code language: PHP (php)
アンダースコアで始まる_updated_atというキーを使いました。これは週のデータとは別の、システム全体の情報であることを示すための慣習です。
index.phpでは、この更新時刻を読み込んで表示します。データが取得できないときは、何も表示しません。
$updatedAt = $data['_updated_at'] ?? '';
Code language: PHP (php)
<?php if ($updatedAt): ?>
<?= htmlspecialchars($updatedAt) ?> 現在
<?php endif; ?>
Code language: HTML, XML (xml)
CSSの外部化
スタイルシートを外部ファイルにすることで、HTMLとCSSの役割を分離しました。index.phpからstyle要素をすべて取り除き、styles.cssという新しいファイルを作成します。
HTMLのhead要素には、外部CSSへのリンクを追加します。
<link rel="stylesheet" href="styles.css">
Code language: HTML, XML (xml)
これで、デザインの変更が必要になったとき、styles.cssだけを編集すればよくなりました。
データ構造の根本的な見直し
ここで、より大きな問題に直面しました。データ構造の問題です。
元のデータ構造は、このようになっていました。
{
"2025-09-29": {
"0": {
"0": "○",
"1": "×",
...
}
}
}
Code language: JavaScript (javascript)
最初の数字が時間帯、次の数字が曜日を表します。つまり、「時間帯ごとに各曜日のデータがまとまっている」構造でした。
しかし、実際にデータを見るとき、「月曜日のスケジュール」「火曜日のスケジュール」というように曜日ごとに考える方が自然です。現在の構造では、1つの曜日のデータを見るために、すべての時間帯を順番に確認する必要がありました。
そこで、構造を逆転させます。「週 → 曜日 → 時間帯」という順序に変更しました。
{
"2025-09-29": {
"is_draft": true,
"schedule": {
"mon": [1, 0, 1, 0],
"tue": [0, 1, 1, 0],
"wed": [1, 1, 0, 1],
"thu": [0, 1, 1, 1],
"fri": [1, 0, 0, 1]
}
}
}
Code language: JSON / JSON with Comments (json)
曜日には、mon、tue、wed、thu、friという英語の略称を使いました。数字のインデックスよりも、何を表しているかが一目でわかります。
また、○と×の代わりに、0と1の数値を使うことにしました。データとしてシンプルで、処理も高速になります。
チェックボックスの意味の逆転
ここで重要な仕様変更を行いました。チェックボックスの意味を逆にしたのです。
元の設計では、チェックを入れると「空いている(○)」を意味していました。しかし、実際に使ってみると、これは直感に反します。普通、カレンダーやスケジュール帳では、予定がある時間帯に印をつけるからです。
そこで、チェックONが「×(予定あり)」を意味するように変更しました。管理者は「埋まっている時間帯にチェックを入れる」という、より自然な操作ができるようになります。
データでは、チェックON = 1 = ×、チェックOFF = 0 = ○という対応関係になります。
未入力状態の導入
新しい機能として、「未入力」という状態を追加しました。まだスケジュールを登録していない週を、すべて「-」で表示する機能です。
週ごとにis_draftというフラグを持たせます。このフラグがtrueの場合、その週はすべて「-」として表示されます。実際にデータを入力していても、未入力として見せることができます。
function getDefaultWeekData() {
global $dayKeys;
$schedule = [];
foreach ($dayKeys as $day) {
$schedule[$day] = [0, 0, 0, 0];
}
return [
'is_draft' => true,
'schedule' => $schedule
];
}
Code language: PHP (php)
初期状態では、すべてのセルが0(空き)で、未入力フラグがONになっています。
管理画面には、「この週は未入力として表示する」というチェックボックスを追加しました。管理者は、スケジュールを入力した後でも、このチェックを入れることで、公開ページでは「-」として表示させることができます。
<div class="draft-control">
<input type="checkbox"
id="is_draft"
name="is_draft"
<?= $currentData['is_draft'] ? 'checked' : '' ?>>
<label for="is_draft">この週は未入力として表示する</label>
</div>
Code language: JavaScript (javascript)
公開ページでは、未入力フラグを確認してから表示を切り替えます。
if ($weekData['is_draft']) {
$status = '-';
$class = 'draft';
} else {
$value = $weekData['schedule'][$dayKey][$slotIndex] ?? 0;
$status = $value === 0 ? '○' : '×';
$class = $value === 0 ? 'available' : 'unavailable';
}
Code language: PHP (php)
古いデータの自動削除
データが蓄積し続ける問題にも対処しました。4週間分しか表示しないのに、過去のデータがすべて残り続けていたのです。
解決策は、データを保存するときに古いデータを削除することです。今週より前のデータは、もう使うことがないので削除します。
function saveData($data) {
$thisWeekKey = getThisWeekMonday();
foreach ($data as $weekKey => $weekData) {
if ($weekKey !== '_updated_at' && $weekKey < $thisWeekKey) {
unset($data[$weekKey]);
}
}
$data['_updated_at'] = date('Y年n月j日 G時i分');
file_put_contents(DATA_FILE, json_encode($data,
JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
}
Code language: PHP (php)
週のキーは日付形式(YYYY-MM-DD)なので、文字列として比較できます。「今週の月曜日」より小さい(古い)キーを持つデータを削除します。
JSON_UNESCAPED_UNICODEオプションを追加したことにも注目してください。これにより、日本語が文字化けせずに保存されます。
データ構造変更への対応
データ構造を変更したことで、すべてのPHPファイルを修正する必要がありました。
config.phpには、曜日キーの配列を追加しました。
$dayKeys = ['mon', 'tue', 'wed', 'thu', 'fri'];
Code language: PHP (php)
admin.phpの保存処理は、新しい構造に合わせて書き直しました。
foreach ($dayKeys as $dayIndex => $dayKey) {
$data[$weekKey]['schedule'][$dayKey] = [];
foreach ($timeSlots as $slotIndex => $slot) {
$checkboxName = "status_{$dayIndex}_{$slotIndex}";
$data[$weekKey]['schedule'][$dayKey][] =
isset($_POST[$checkboxName]) ? 1 : 0;
}
}
Code language: PHP (php)
index.phpも、新しいデータ構造から値を読み取るように修正しました。
$value = $weekData['schedule'][$dayKey][$slotIndex] ?? 0;
Code language: PHP (php)
スタイルの追加
未入力状態を表示するために、CSSに新しいクラスを追加しました。
.draft {
color: #999;
}
Code language: CSS (css)
グレー色で表示することで、未入力であることが視覚的にわかります。
完成したシステム
改良を重ねた結果、このようなシステムができあがりました。
データ構造は「週 → 曜日 → 時間帯」という自然な順序になり、JSONファイルを直接見ても内容が理解しやすくなりました。チェックボックスの意味も直感的になり、管理者は予定がある時間帯にチェックを入れるだけです。
未入力状態の機能により、まだスケジュールを決めていない週を「-」として表示できます。古いデータは自動的に削除されるため、ファイルサイズが無制限に大きくなることもありません。
そして、ページ間のリンクとCSS外部化により、保守性も向上しました。
まとめ
週間スケジュール管理システムの改良により、データ構造を「週→曜日→時間帯」の自然な順序に再設計し、値を0/1の数値表現に統一しました。未入力状態を表すis_draftフラグを週単位で管理し、公開ページでは「-」として表示する機能を実装しました。データ保存時に今週より前の週を自動削除する機能により、JSONファイルの肥大化を防止しています。チェックボックスの意味を逆転させ、チェックON=1=×(予定あり)とすることで、より直感的な操作を実現しました。