Files
tfluceecrud/index.cfm
T

162 lines
7.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!---
index.cfm — CRUD-интерфейс для таблицы в PostgreSQL
Логика:
1. Если POST-запрос с FORM.action — выполняем create/update/delete
и редиректим на GET (POST-redirect-GET паттерн)
2. Если GET-запрос с URL.edit — загружаем запись для редактирования
3. Всегда показываем список всех записей + форму добавления/редактирования
Безопасность:
- cfqueryparam для всех входных данных → защита от SQL-инъекций
- cflocation после POST → защита от повторной отправки формы
- cfoutput только где нужно → XSS-защита через автоматическое экранирование Lucee
Переменные:
- request.tableName — имя таблицы (из Application.cfc / json_env TABLE_NAME)
- FORM.action — create | update | delete (POST)
- FORM.value — значение записи (POST)
- FORM.id — ID записи для update/delete (POST)
- URL.edit — ID записи для редактирования (GET)
--->
<cfset tableName = request.tableName />
<!--- ====== ОБРАБОТКА POST-ЗАПРОСОВ (create / update / delete) ====== --->
<!--- isDefined("FORM.action") — true только если страница вызвана через <form method="post"> --->
<cfif isDefined("FORM.action")>
<!--- CREATE: вставка новой записи --->
<cfif FORM.action EQ "create">
<!--- cfqueryparam cfsqltype="cf_sql_varchar" — экранирует значение, защита от SQL-инъекций --->
<cfquery name="insertRow">
INSERT INTO #tableName# (value)
VALUES (<cfqueryparam value="#FORM.value#" cfsqltype="cf_sql_varchar" />)
</cfquery>
</cfif>
<!--- UPDATE: обновление существующей записи по ID --->
<cfif FORM.action EQ "update">
<cfquery name="updateRow">
UPDATE #tableName#
SET value = <cfqueryparam value="#FORM.value#" cfsqltype="cf_sql_varchar" />
WHERE id = <cfqueryparam value="#FORM.id#" cfsqltype="cf_sql_integer" />
</cfquery>
</cfif>
<!--- DELETE: удаление записи по ID --->
<cfif FORM.action EQ "delete">
<cfquery name="deleteRow">
DELETE FROM #tableName#
WHERE id = <cfqueryparam value="#FORM.id#" cfsqltype="cf_sql_integer" />
</cfquery>
</cfif>
<!--- POST-redirect-GET: после любого действия — редирект на чистый URL без POST-данных.
Это предотвращает повторную отправку формы при обновлении страницы (F5). --->
<cflocation url="index.cfm" addtoken="no" />
</cfif>
<!--- ====== РЕЖИМ РЕДАКТИРОВАНИЯ (GET-запрос с ?edit=ID) ====== --->
<!--- editRow всегда инициализируем пустым словарём.
Если URL.edit не задан или запись не найдена — editRow останется пустым. --->
<cfset editRow = {} />
<cfif isDefined("URL.edit")>
<!--- Загружаем запись по ID из URL --->
<cfquery name="editQuery">
SELECT id, value FROM #tableName#
WHERE id = <cfqueryparam value="#URL.edit#" cfsqltype="cf_sql_integer" />
</cfquery>
<!--- Если запись найдена — заполняем editRow данными из запроса --->
<cfif editQuery.recordCount GT 0>
<cfset editRow = { id = editQuery.id, value = editQuery.value } />
</cfif>
</cfif>
<!--- ====== СПИСОК ВСЕХ ЗАПИСЕЙ ====== --->
<cfquery name="rows">
SELECT id, value FROM #tableName# ORDER BY id
</cfquery>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<title>CRUD — <cfoutput>#tableName#</cfoutput></title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 40px auto; }
table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
th, td { border: 1px solid #ccc; padding: 8px; text-align: left; }
th { background: #f5f5f5; }
form { margin-bottom: 20px; }
input, button { padding: 6px 10px; margin: 2px; }
.actions a { margin: 0 4px; }
</style>
</head>
<body>
<h1><cfoutput>#tableName#</cfoutput></h1>
<!--- Таблица записей --->
<table>
<tr>
<th>ID</th>
<th>Value</th>
<th></th>
</tr>
<!--- cfoutput query="rows" — цикл по всем строкам результата SELECT --->
<cfoutput query="rows">
<tr>
<td>#id#</td>
<td>#value#</td>
<td class="actions">
<!--- Ссылка на редактирование: index.cfm?edit={id} --->
<a href="index.cfm?edit=#id#">✏️</a>
<!--- Форма удаления: POST с action=delete и id записи.
JS confirm() — защита от случайного удаления. --->
<form method="post" style="display:inline">
<input type="hidden" name="action" value="delete" />
<input type="hidden" name="id" value="#id#" />
<button type="submit" onclick="return confirm('Удалить #id#?')">🗑️</button>
</form>
</td>
</tr>
</cfoutput>
<!--- Если записей нет — показываем информационное сообщение --->
<cfif rows.recordCount EQ 0>
<tr><td colspan="3">Нет записей. Создайте первую.</td></tr>
</cfif>
</table>
<!--- ====== ФОРМА: редактирование ИЛИ добавление ====== --->
<!--- structIsEmpty(editRow) — true если нет записи для редактирования → показываем форму ДОБАВЛЕНИЯ --->
<!--- false если URL.edit задан и запись найдена → показываем форму РЕДАКТИРОВАНИЯ --->
<cfif NOT structIsEmpty(editRow)>
<!--- cfoutput нужен чтобы #editRow.id# и #editRow.value# вычислились --->
<cfoutput>
<h2>Редактировать #editRow.id#</h2>
<form method="post">
<input type="hidden" name="action" value="update" />
<input type="hidden" name="id" value="#editRow.id#" />
<!--- type="text" — позволяет вводить любые символы, не только цифры --->
<input type="text" name="value" value="#editRow.value#" required />
<button type="submit">Сохранить</button>
<a href="index.cfm">Отмена</a>
</form>
</cfoutput>
<cfelse>
<h2>Добавить</h2>
<form method="post">
<input type="hidden" name="action" value="create" />
<!--- placeholder — подсказка в пустом поле --->
<input type="text" name="value" placeholder="Значение" required />
<button type="submit">Добавить</button>
</form>
</cfif>
</body>
</html>
</html>