no message
This commit is contained in:
167
public/index.php
Normal file
167
public/index.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/**
|
||||
* トップページ
|
||||
*
|
||||
* 商品管理システムのメインページです。
|
||||
*/
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>商品管理システム - PHP・DB連携演習</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.container {
|
||||
max-width: 900px;
|
||||
width: 100%;
|
||||
background: white;
|
||||
padding: 40px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 15px 35px rgba(0,0,0,0.3);
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
font-size: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
.subtitle {
|
||||
color: #666;
|
||||
margin-bottom: 40px;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
.menu-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.menu-card {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
transition: transform 0.3s, box-shadow 0.3s;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
.menu-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
|
||||
}
|
||||
.menu-card .icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.menu-card h2 {
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.menu-card p {
|
||||
font-size: 14px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.advanced-section {
|
||||
margin-top: 40px;
|
||||
padding-top: 30px;
|
||||
border-top: 2px solid #eee;
|
||||
}
|
||||
.advanced-section h3 {
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.advanced-card {
|
||||
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
|
||||
}
|
||||
.info-box {
|
||||
background: #e7f3ff;
|
||||
border-left: 4px solid #2196F3;
|
||||
padding: 20px;
|
||||
margin-top: 30px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.info-box h3 {
|
||||
color: #1976D2;
|
||||
margin-bottom: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.info-box p {
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🏪 商品管理システム</h1>
|
||||
<p class="subtitle">PHP・DB連携 総合演習課題</p>
|
||||
|
||||
<div class="menu-grid">
|
||||
<a href="product_list.php" class="menu-card">
|
||||
<div class="icon">📋</div>
|
||||
<h2>商品一覧</h2>
|
||||
<p>登録されている商品を表示<br>(実装済み・参考用)</p>
|
||||
</a>
|
||||
|
||||
<a href="product_register.php" class="menu-card">
|
||||
<div class="icon">📝</div>
|
||||
<h2>商品登録</h2>
|
||||
<p>新しい商品を登録する<br>(ステップ2)</p>
|
||||
</a>
|
||||
|
||||
<a href="product_update.php" class="menu-card">
|
||||
<div class="icon">✏️</div>
|
||||
<h2>商品更新</h2>
|
||||
<p>既存の商品情報を更新<br>(ステップ3)</p>
|
||||
</a>
|
||||
|
||||
<a href="product_delete.php" class="menu-card">
|
||||
<div class="icon">🗑️</div>
|
||||
<h2>商品削除</h2>
|
||||
<p>商品を削除する<br>(ステップ4)</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="advanced-section">
|
||||
<h3>🎓 追加課題</h3>
|
||||
<div class="menu-grid">
|
||||
<a href="product_join.php" class="menu-card advanced-card">
|
||||
<div class="icon">🔗</div>
|
||||
<h2>JOIN検索</h2>
|
||||
<p>複数テーブルを結合した<br>高度な検索機能</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>📚 学習の進め方</h3>
|
||||
<p>
|
||||
<strong>1.</strong> まず「商品一覧」のコードを読んで理解しましょう<br>
|
||||
<strong>2.</strong> 「商品登録」→「商品更新」→「商品削除」の順に実装しましょう<br>
|
||||
<strong>3.</strong> 基本課題が完了したら「JOIN検索」に挑戦しましょう<br>
|
||||
<strong>4.</strong> 各ファイルのTODOコメントを参考に実装してください
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
337
public/product_delete.php
Normal file
337
public/product_delete.php
Normal file
@@ -0,0 +1,337 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../database/products/ProductAccess.php';
|
||||
|
||||
/**
|
||||
* 商品削除処理(Delete)
|
||||
*
|
||||
* このファイルでは、既存の商品をデータベースから削除します。
|
||||
*/
|
||||
|
||||
// エラー表示設定(開発時のみ)
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$message = '';
|
||||
$messageType = '';
|
||||
$product = null;
|
||||
|
||||
// POSTリクエストの処理(削除実行)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete'])) {
|
||||
try {
|
||||
$id = (int)$_POST['id'];
|
||||
|
||||
// TODO: ProductAccessのインスタンスを作成してください
|
||||
$productAccess = null; // ここを実装
|
||||
|
||||
// TODO: productAccessのdelete()メソッドを呼び出して商品を削除してください
|
||||
|
||||
$message = "商品を削除しました!";
|
||||
$messageType = "success";
|
||||
$product = null; // 削除後は商品情報をクリア
|
||||
|
||||
} catch (Exception $e) {
|
||||
// TODO: エラーメッセージを$messageに設定してください
|
||||
$message = "";
|
||||
$messageType = "error";
|
||||
}
|
||||
}
|
||||
|
||||
// GETリクエストの処理(商品情報取得)
|
||||
if (isset($_GET['id']) && empty($_POST)) {
|
||||
try {
|
||||
$id = (int)$_GET['id'];
|
||||
$productAccess = new ProductAccess();
|
||||
$product = $productAccess->read($id);
|
||||
|
||||
if (empty($product)) {
|
||||
$message = "指定された商品が見つかりませんでした。";
|
||||
$messageType = "error";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$message = "商品の取得に失敗しました: " . $e->getMessage();
|
||||
$messageType = "error";
|
||||
}
|
||||
}
|
||||
|
||||
// 全商品一覧を取得(セレクトボックス用)
|
||||
$products = [];
|
||||
$categories = [];
|
||||
try {
|
||||
$productAccess = new ProductAccess();
|
||||
$products = $productAccess->read();
|
||||
$categoriesData = $productAccess->getCategories();
|
||||
foreach ($categoriesData as $cat) {
|
||||
$categories[$cat['id']] = $cat['name'];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$message = "データの取得に失敗しました: " . $e->getMessage();
|
||||
$messageType = "error";
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>商品削除 - CRUD操作</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
margin-bottom: 25px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 25px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
padding: 8px 16px;
|
||||
background: #667eea;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.message.success {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.message.error {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
select:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 12px 24px;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.btn-search {
|
||||
background: #667eea;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.btn-search:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #e74c3c;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: #c0392b;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.product-info h3 {
|
||||
margin-bottom: 15px;
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: bold;
|
||||
width: 120px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
flex: 1;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background: #fff3cd;
|
||||
border: 1px solid #ffc107;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 20px;
|
||||
color: #856404;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🗑️ 商品削除</h1>
|
||||
<p class="subtitle">Delete - 既存の商品を削除します</p>
|
||||
|
||||
<div class="nav-links">
|
||||
<a href="index.php">🏠 トップ</a>
|
||||
<a href="product_list.php">📋 一覧表示</a>
|
||||
<a href="product_register.php">📝 新規登録</a>
|
||||
<a href="product_update.php">✏️ 更新</a>
|
||||
<a href="product_join.php">🔗 JOIN検索</a>
|
||||
</div>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="message <?php echo $messageType; ?>">
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 商品選択セクション -->
|
||||
<div class="section">
|
||||
<h2>1. 削除する商品を選択</h2>
|
||||
<form method="GET" action="">
|
||||
<div class="form-group">
|
||||
<label for="product_select">商品選択</label>
|
||||
<select name="id" id="product_select">
|
||||
<option value="">選択してください</option>
|
||||
<?php foreach ($products as $p): ?>
|
||||
<option value="<?php echo $p['id']; ?>"
|
||||
<?php echo (isset($_GET['id']) && $_GET['id'] == $p['id']) ? 'selected' : ''; ?>>
|
||||
[ID: <?php echo $p['id']; ?>] <?php echo htmlspecialchars($p['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-search">商品情報を取得</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 削除確認セクション -->
|
||||
<?php if ($product): ?>
|
||||
<div class="section">
|
||||
<h2>2. 削除確認</h2>
|
||||
|
||||
<div class="warning">
|
||||
⚠️ この操作は取り消せません。本当に削除してよろしいですか?
|
||||
</div>
|
||||
|
||||
<div class="product-info">
|
||||
<h3>削除対象の商品情報</h3>
|
||||
<div class="info-row">
|
||||
<span class="info-label">商品ID:</span>
|
||||
<span class="info-value"><?php echo htmlspecialchars($product['id']); ?></span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">カテゴリ:</span>
|
||||
<span class="info-value"><?php echo htmlspecialchars($categories[$product['category_id']] ?? '不明'); ?></span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">商品名:</span>
|
||||
<span class="info-value"><?php echo htmlspecialchars($product['name']); ?></span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">説明:</span>
|
||||
<span class="info-value"><?php echo htmlspecialchars($product['description'] ?? '-'); ?></span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">価格:</span>
|
||||
<span class="info-value">¥<?php echo number_format($product['price']); ?></span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">在庫数:</span>
|
||||
<span class="info-value"><?php echo htmlspecialchars($product['stock']); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="" onsubmit="return confirm('本当に削除しますか?');">
|
||||
<input type="hidden" name="id" value="<?php echo $product['id']; ?>">
|
||||
<button type="submit" name="delete" class="btn btn-danger">削除する</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
348
public/product_join.php
Normal file
348
public/product_join.php
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../database/products/ProductAccess.php';
|
||||
|
||||
/**
|
||||
* JOIN を使った高度な検索(追加課題)
|
||||
*
|
||||
* このファイルでは、categoriesテーブルとproductsテーブルを結合して、
|
||||
* カテゴリ情報と共に商品情報を取得します。
|
||||
* また、カテゴリ別の商品数を集計する機能も実装します。
|
||||
*/
|
||||
|
||||
// エラー表示設定(開発時のみ)
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$message = '';
|
||||
$messageType = '';
|
||||
$productsWithCategory = [];
|
||||
$categoryStats = [];
|
||||
|
||||
try {
|
||||
// ProductAccessを使ってPDO接続を取得
|
||||
$productAccess = new ProductAccess();
|
||||
$pdo = $productAccess->getConnection();
|
||||
|
||||
// TODO: INNER JOINを使って、商品情報とカテゴリ情報を結合して取得してください
|
||||
$sql = ""; // ここにJOINを使ったSQL文を記述
|
||||
|
||||
// TODO: ここでSQLを実行して結果を$productsWithCategoryに格納
|
||||
|
||||
|
||||
// TODO: カテゴリ別の商品数と平均価格を集計してください
|
||||
$statsSql = ""; // ここに集計用のSQL文を記述
|
||||
|
||||
// TODO: ここでSQLを実行して結果を$categoryStatsに格納
|
||||
} catch (Exception $e) {
|
||||
$message = "データの取得に失敗しました: " . $e->getMessage();
|
||||
$messageType = "error";
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>JOIN検索 - 追加課題</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #555;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 15px;
|
||||
font-size: 22px;
|
||||
border-bottom: 2px solid #11998e;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
margin-bottom: 25px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 25px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
padding: 8px 16px;
|
||||
background: #11998e;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
background: #0e7d72;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.message.error {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th {
|
||||
background: #11998e;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.price {
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.stock {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.category-badge {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
background: #11998e;
|
||||
color: white;
|
||||
border-radius: 15px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.stat-card h3 {
|
||||
margin-bottom: 15px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.stat-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.stat-row:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #999;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: #e7f3ff;
|
||||
border-left: 4px solid #2196F3;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.info-box h3 {
|
||||
color: #1976D2;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.info-box p {
|
||||
color: #555;
|
||||
line-height: 1.6;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🔗 JOIN を使った高度な検索</h1>
|
||||
<p class="subtitle">Advanced - 複数テーブルを結合してデータを取得します</p>
|
||||
|
||||
<div class="nav-links">
|
||||
<a href="index.php">🏠 トップ</a>
|
||||
<a href="product_list.php">📋 一覧表示</a>
|
||||
<a href="product_register.php">📝 新規登録</a>
|
||||
<a href="product_update.php">✏️ 更新</a>
|
||||
<a href="product_delete.php">🗑️ 削除</a>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<h3>📚 追加課題のポイント</h3>
|
||||
<p>
|
||||
この課題では、<strong>INNER JOIN</strong> と <strong>LEFT JOIN</strong> を使用します。<br>
|
||||
・INNER JOIN: カテゴリと商品の両方に存在するデータのみを取得<br>
|
||||
・LEFT JOIN: 全カテゴリを取得し、商品がない場合も表示<br>
|
||||
・集計関数: COUNT()で商品数、AVG()で平均価格を計算<br>
|
||||
・GROUP BY: カテゴリごとにグループ化
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="message <?php echo $messageType; ?>">
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- カテゴリ別統計情報 -->
|
||||
<h2>📊 カテゴリ別統計情報</h2>
|
||||
<?php if (empty($categoryStats)): ?>
|
||||
<div class="no-data">
|
||||
統計情報を表示できません。<br>
|
||||
TODOを実装してください。
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="stats-grid">
|
||||
<?php foreach ($categoryStats as $stat): ?>
|
||||
<div class="stat-card">
|
||||
<h3><?php echo htmlspecialchars($stat['name']); ?></h3>
|
||||
<div class="stat-row">
|
||||
<span class="stat-label">商品数:</span>
|
||||
<span class="stat-value"><?php echo $stat['product_count']; ?> 件</span>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-label">平均価格:</span>
|
||||
<span class="stat-value">
|
||||
<?php
|
||||
echo $stat['avg_price']
|
||||
? '¥' . number_format($stat['avg_price'], 0)
|
||||
: '商品なし';
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 商品一覧(カテゴリ情報付き) -->
|
||||
<h2>📦 商品一覧(カテゴリ情報付き)</h2>
|
||||
<?php if (empty($productsWithCategory)): ?>
|
||||
<div class="no-data">
|
||||
商品情報を表示できません。<br>
|
||||
TODOを実装してください。
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>カテゴリ</th>
|
||||
<th>商品名</th>
|
||||
<th>カテゴリ説明</th>
|
||||
<th>価格</th>
|
||||
<th>在庫</th>
|
||||
<th>登録日時</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($productsWithCategory as $product): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($product['id']); ?></td>
|
||||
<td>
|
||||
<span class="category-badge">
|
||||
<?php echo htmlspecialchars($product['category_name']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo htmlspecialchars($product['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['category_description'] ?? '-'); ?></td>
|
||||
<td class="price">¥<?php echo number_format($product['price']); ?></td>
|
||||
<td class="stock"><?php echo htmlspecialchars($product['stock']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['created_at']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<p style="margin-top: 15px; color: #666; font-size: 14px;">
|
||||
全 <?php echo count($productsWithCategory); ?> 件の商品が表示されています。
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
220
public/product_list.php
Normal file
220
public/product_list.php
Normal file
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../database/products/ProductAccess.php';
|
||||
|
||||
/**
|
||||
* 商品一覧表示処理(Read)
|
||||
*
|
||||
* このファイルでは、登録されている全商品をデータベースから取得して表示します。
|
||||
* このファイルは実装済みです。他のファイルを実装する際の参考にしてください。
|
||||
*/
|
||||
|
||||
// エラー表示設定(開発時のみ)
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$products = [];
|
||||
$categories = [];
|
||||
$message = '';
|
||||
$messageType = '';
|
||||
|
||||
try {
|
||||
// ProductAccessのインスタンスを作成
|
||||
$productAccess = new ProductAccess();
|
||||
|
||||
// read()メソッドを呼び出して全商品を取得
|
||||
// 引数を渡さない(またはnullを渡す)と全件取得できます
|
||||
$products = $productAccess->read();
|
||||
|
||||
// カテゴリ一覧も取得
|
||||
$categoriesData = $productAccess->getCategories();
|
||||
foreach ($categoriesData as $cat) {
|
||||
$categories[$cat['id']] = $cat['name'];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// エラーメッセージを設定
|
||||
$message = "商品の取得に失敗しました: " . $e->getMessage();
|
||||
$messageType = "error";
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>商品一覧 - CRUD操作</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
margin-bottom: 25px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 25px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
padding: 8px 16px;
|
||||
background: #667eea;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.message.error {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.price {
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.stock {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #999;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.count {
|
||||
margin-top: 15px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>📋 商品一覧</h1>
|
||||
<p class="subtitle">Read - 登録されている商品を表示します(実装済み・参考用)</p>
|
||||
|
||||
<div class="nav-links">
|
||||
<a href="index.php">🏠 トップ</a>
|
||||
<a href="product_register.php">📝 新規登録</a>
|
||||
<a href="product_update.php">✏️ 更新</a>
|
||||
<a href="product_delete.php">🗑️ 削除</a>
|
||||
<a href="product_join.php">🔗 JOIN検索</a>
|
||||
</div>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="message <?php echo $messageType; ?>">
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (empty($products)): ?>
|
||||
<div class="no-data">
|
||||
商品が登録されていません。<br>
|
||||
<a href="product_register.php">こちら</a>から商品を登録してください。
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>カテゴリ</th>
|
||||
<th>商品名</th>
|
||||
<th>説明</th>
|
||||
<th>価格</th>
|
||||
<th>在庫</th>
|
||||
<th>登録日時</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($products as $product): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($product['id']); ?></td>
|
||||
<td><?php echo htmlspecialchars($categories[$product['category_id']] ?? '不明'); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['description'] ?? '-'); ?></td>
|
||||
<td class="price">¥<?php echo number_format($product['price']); ?></td>
|
||||
<td class="stock"><?php echo htmlspecialchars($product['stock']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['created_at']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="count">全 <?php echo count($products); ?> 件の商品が登録されています。</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
247
public/product_register.php
Normal file
247
public/product_register.php
Normal file
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../database/products/ProductAccess.php';
|
||||
|
||||
/**
|
||||
* 商品登録処理(Create)
|
||||
*
|
||||
* このファイルでは、新しい商品をデータベースに登録します。
|
||||
*/
|
||||
|
||||
// エラー表示設定(開発時のみ)
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$message = '';
|
||||
$messageType = '';
|
||||
|
||||
// POSTリクエストの処理
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
try {
|
||||
// TODO: ProductAccessのインスタンスを作成してください
|
||||
$productAccess = null; // ここを実装
|
||||
|
||||
// TODO: POSTデータから商品情報を配列にまとめてください
|
||||
// 必要な情報: category_id, name, description, price, stock
|
||||
$productData = [
|
||||
// ここにPOSTデータを設定
|
||||
];
|
||||
|
||||
// TODO: productAccessのcreate()メソッドを呼び出して商品を登録してください
|
||||
|
||||
|
||||
// 成功メッセージ
|
||||
$message = "商品を登録しました!";
|
||||
$messageType = "success";
|
||||
} catch (Exception $e) {
|
||||
// TODO: エラーメッセージを$messageに設定してください
|
||||
$message = "";
|
||||
$messageType = "error";
|
||||
}
|
||||
}
|
||||
|
||||
// カテゴリ一覧を取得(セレクトボックス用)
|
||||
$categories = [];
|
||||
try {
|
||||
$productAccess = new ProductAccess();
|
||||
$categories = $productAccess->getCategories();
|
||||
} catch (Exception $e) {
|
||||
$message = "カテゴリの取得に失敗しました: " . $e->getMessage();
|
||||
$messageType = "error";
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>商品登録 - CRUD操作</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
margin-bottom: 25px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 25px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
padding: 8px 16px;
|
||||
background: #667eea;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.message.success {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.message.error {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
input[type="text"]:focus,
|
||||
input[type="number"]:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background: #667eea;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>📝 商品登録</h1>
|
||||
<p class="subtitle">Create - 新しい商品を登録します</p>
|
||||
|
||||
<div class="nav-links">
|
||||
<a href="index.php">🏠 トップ</a>
|
||||
<a href="product_list.php">📋 一覧表示</a>
|
||||
<a href="product_update.php">✏️ 更新</a>
|
||||
<a href="product_delete.php">🗑️ 削除</a>
|
||||
<a href="product_join.php">🔗 JOIN検索</a>
|
||||
</div>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="message <?php echo $messageType; ?>">
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="product_register.php">
|
||||
<div class="form-group">
|
||||
<label for="category_id">カテゴリ *</label>
|
||||
<select name="category_id" id="category_id" required>
|
||||
<option value="">選択してください</option>
|
||||
<?php foreach ($categories as $category): ?>
|
||||
<option value="<?php echo $category['id']; ?>">
|
||||
<?php echo htmlspecialchars($category['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">商品名 *</label>
|
||||
<input type="text" name="name" id="name" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">説明</label>
|
||||
<textarea name="description" id="description"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="price">価格 *</label>
|
||||
<input type="number" name="price" id="price" step="0.01" min="0" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="stock">在庫数 *</label>
|
||||
<input type="number" name="stock" id="stock" min="0" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn">登録する</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
310
public/product_update.php
Normal file
310
public/product_update.php
Normal file
@@ -0,0 +1,310 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../database/products/ProductAccess.php';
|
||||
|
||||
/**
|
||||
* 商品更新処理(Update)
|
||||
*
|
||||
* このファイルでは、既存の商品情報を更新します。
|
||||
*/
|
||||
|
||||
// エラー表示設定(開発時のみ)
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$message = '';
|
||||
$messageType = '';
|
||||
$product = null;
|
||||
|
||||
// POSTリクエストの処理(更新実行)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update'])) {
|
||||
try {
|
||||
$id = (int)$_POST['id'];
|
||||
|
||||
// TODO: ProductAccessのインスタンスを作成してください
|
||||
$productAccess = null; // ここを実装
|
||||
|
||||
// TODO: POSTデータから商品情報を配列にまとめてください
|
||||
$productData = [
|
||||
// ここにPOSTデータを設定
|
||||
];
|
||||
|
||||
// TODO: productAccessのupdate()メソッドを呼び出して商品を更新してください
|
||||
|
||||
|
||||
$message = "商品情報を更新しました!";
|
||||
$messageType = "success";
|
||||
} catch (Exception $e) {
|
||||
// TODO: エラーメッセージを$messageに設定してください
|
||||
$message = "";
|
||||
$messageType = "error";
|
||||
}
|
||||
}
|
||||
|
||||
// GETリクエストの処理(商品情報取得)
|
||||
if (isset($_GET['id'])) {
|
||||
try {
|
||||
$id = (int)$_GET['id'];
|
||||
|
||||
// TODO: ProductAccessのインスタンスを作成してください
|
||||
$productAccess = null; // ここを実装
|
||||
|
||||
// TODO: productAccessのread()メソッドを呼び出して商品情報を取得してください
|
||||
$product = null; // ここを実装
|
||||
|
||||
if (empty($product)) {
|
||||
$message = "指定された商品が見つかりませんでした。";
|
||||
$messageType = "error";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$message = "商品の取得に失敗しました: " . $e->getMessage();
|
||||
$messageType = "error";
|
||||
}
|
||||
}
|
||||
|
||||
// 全商品一覧を取得(セレクトボックス用)
|
||||
$products = [];
|
||||
$categories = [];
|
||||
try {
|
||||
$productAccess = new ProductAccess();
|
||||
$products = $productAccess->read();
|
||||
$categories = $productAccess->getCategories();
|
||||
} catch (Exception $e) {
|
||||
$message = "データの取得に失敗しました: " . $e->getMessage();
|
||||
$messageType = "error";
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>商品更新 - CRUD操作</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
margin-bottom: 25px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 25px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
padding: 8px 16px;
|
||||
background: #667eea;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.message.success {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.message.error {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
input[type="text"]:focus,
|
||||
input[type="number"]:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 12px 24px;
|
||||
background: #667eea;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
|
||||
.btn-search {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>✏️ 商品更新</h1>
|
||||
<p class="subtitle">Update - 既存の商品情報を更新します</p>
|
||||
|
||||
<div class="nav-links">
|
||||
<a href="index.php">🏠 トップ</a>
|
||||
<a href="product_list.php">📋 一覧表示</a>
|
||||
<a href="product_register.php">📝 新規登録</a>
|
||||
<a href="product_delete.php">🗑️ 削除</a>
|
||||
<a href="product_join.php">🔗 JOIN検索</a>
|
||||
</div>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="message <?php echo $messageType; ?>">
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- 商品選択セクション -->
|
||||
<div class="section">
|
||||
<h2>1. 更新する商品を選択</h2>
|
||||
<form method="GET" action="">
|
||||
<div class="form-group">
|
||||
<label for="product_select">商品選択</label>
|
||||
<select name="id" id="product_select">
|
||||
<option value="">選択してください</option>
|
||||
<?php foreach ($products as $p): ?>
|
||||
<option value="<?php echo $p['id']; ?>"
|
||||
<?php echo (isset($_GET['id']) && $_GET['id'] == $p['id']) ? 'selected' : ''; ?>>
|
||||
[ID: <?php echo $p['id']; ?>] <?php echo htmlspecialchars($p['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-search">商品情報を取得</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 更新フォームセクション -->
|
||||
<?php if ($product): ?>
|
||||
<div class="section">
|
||||
<h2>2. 商品情報を更新</h2>
|
||||
<form method="POST" action="">
|
||||
<input type="hidden" name="id" value="<?php echo $product['id']; ?>">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="category_id">カテゴリ *</label>
|
||||
<select name="category_id" id="category_id" required>
|
||||
<?php foreach ($categories as $category): ?>
|
||||
<option value="<?php echo $category['id']; ?>"
|
||||
<?php echo ($product['category_id'] == $category['id']) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($category['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">商品名 *</label>
|
||||
<input type="text" name="name" id="name"
|
||||
value="<?php echo htmlspecialchars($product['name']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">説明</label>
|
||||
<textarea name="description" id="description"><?php echo htmlspecialchars($product['description'] ?? ''); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="price">価格 *</label>
|
||||
<input type="number" name="price" id="price" step="0.01" min="0"
|
||||
value="<?php echo $product['price']; ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="stock">在庫数 *</label>
|
||||
<input type="number" name="stock" id="stock" min="0"
|
||||
value="<?php echo $product['stock']; ?>" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" name="update" class="btn">更新する</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user